Преобразование Vec <String> в Vec <& str>

Я могу преобразовать Vec<String> в Vec<&str> следующим образом:

let mut items = Vec::<&str>::new();
for item in &another_items {
    items.push(item);
}

Я предполагаю, что есть лучшие альтернативы?

Ответы

Ответ 1

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

Это разделение s (которое имеет тип &String) на ссылку String "с правой стороны", которое затем разыменовывается с помощью символа Deref на ссылку str "с правой стороны" а затем снова обратился в &str. Это то, что очень часто встречается в компиляторе, и поэтому я считаю его идиоматичным.

let v2: Vec<&str> = v.iter().map(|s| &**s).collect();

Здесь функция Deref признака Deref передается функции map. Это довольно аккуратно, но требует use использования признака или полного пути.

let v3: Vec<&str> = v.iter().map(std::ops::Deref::deref).collect();

Это устарело, вы не должны этого делать, поскольку это может быть сделано в будущем с помощью |s| s: &str (синтаксис принуждения).

let v4: Vec<&str> = v.iter().map(|s| s as &str).collect();

Это занимает фрагмент RangeFull String (всего лишь фрагмент во весь String) и ссылается на него. Это уродливо, на мой взгляд.

let v5: Vec<&str> = v.iter().map(|s| &s[..]).collect();

Это использует принуждения для преобразования a &String в &str. Также может быть заменен выражением s: &str в будущем.

let v6: Vec<&str> = v.iter().map(|s| { let s: &str = s; s }).collect();

В следующем (спасибо @huon-dbaupp) используется признак AsRef, который существует только для сопоставления принадлежащих им типов с их соответствующим заимствованным типом. Есть два способа использовать его, и снова, симпатия любой версии полностью субъективна.

let v7: Vec<&str> = v.iter().map(|s| s.as_ref()).collect();

и

let v8: Vec<&str> = v.iter().map(AsRef::as_ref).collect();

В моей нижней строке используется решение v8, так как оно явно выражает то, что вы хотите.

Ответ 2

Другие ответы просто работают. Я просто хочу указать, что если вы пытаетесь преобразовать Vec<String> в Vec<&str> только для передачи его функции, принимающей Vec<&str> в качестве аргумента, рассмотрите пересмотр сигнатуры функции как:

fn my_func<T: AsRef<str>>(list: &[T]) { ... }

вместо:

fn my_func(list: &Vec<&str>) { ... }

Как отметил этот вопрос: Функция, взявшая как принадлежащие, так и не принадлежащие коллекции строк. Таким образом, оба вектора просто работают без необходимости преобразований.

Ответ 3

another_items.iter().map(|item| item.deref()).collect::<Vec<&str>>()

Чтобы использовать deref(), вы должны добавить с помощью use std::ops::Deref

Ответ 4

Этот использует collect:

let strs: Vec<&str> = another_items.iter().map(|s| s as &str).collect();

Ответ 5

Вот еще один вариант:

use std::iter::FromIterator;

let v = Vec::from_iter(v.iter().map(String::as_str));

Обратите внимание, что String::as_str является стабильным с Rust 1.7.