Как я могу привести типы элементов итератора к новому типу? - PullRequest
0 голосов
/ 06 июня 2019

Проведение экспериментов с новыми типами и поиск наиболее эффективного и эргономичного способа преобразования элементов в коллекциях. Для единичных значений вполне нормально работают стандартные черты преобразования типов:

pub struct Tag(String);

impl From<Tag> for String {
    fn from(v: Tag) -> String {
        v.0
    }
}

impl From<String> for Tag {
    fn from(v: String) -> Tag {
        Tag(v)
    }
}

impl AsRef<String> for Tag {
    fn as_ref(&self) -> &String {
        &self.0
    }
}

impl<'a> From<&'a Tag> for String {
    fn from(t: &Tag) -> String {
        t.0.clone()
    }
}

Но я начинаю сталкиваться с проблемами, когда хочу разобраться со списками предметов. Скажем (в целях иллюстрации) у меня есть функция, которая обрабатывает теги, и еще несколько абстрактных функций, которые занимаются записью строк в БД:

fn process_item(tags: &Vec<Tag>) {
    process_array_of_strings(tags);
}

fn process_array_of_strings(strings: &Vec<String>) {
    // ...
}

Это не скомпилируется, потому что Rust не может привести tags к Vec<String>, и мне кажется, что должен быть способ сделать это более легко, чем:

fn process_item(tags: &Vec<Tag>) {
    let str_tags: Vec<String> = tags.iter().map(|t| t.into()).collect();
    process_array_of_strings(&str_tags);
}

... который помимо многословности включает в себя гораздо больше промежуточной памяти, чем мне бы хотелось. Обратное преобразование также является проблемой, но предположительно будет реализовано таким же образом.

Здесь могут присутствовать некоторые дополнительные вещи, например, следует ли мне отправлять Vec ссылок, а не значений, и действительно ли это хорошая идея для реализации преобразования типов из ссылочных типов.

1 Ответ

1 голос
/ 06 июня 2019

Простой, просто используйте generic:

pub struct Tag(String);

impl AsRef<str> for Tag {
    fn as_ref(&self) -> &str {
        &self.0
    }
}

fn process_item(tags: &[Tag]) {
    process_array_of_strings(tags);
}

fn process_array_of_strings<'a, T>(strings: &[T])
where
    T: AsRef<str>,
{
    // ...
}
...