Преобразовать Vec <String> в фрагмент & str в Rust?

Per Стив Клабник записывает в документации до Rust 1.0 разницу между String и &str, в Rust вы должны используйте &str, если вам действительно не требуется владение над String. Точно так же рекомендуется использовать ссылки на срезы (&[]) вместо Vec, если вам действительно не требуется владение над Vec.

У меня есть Vec<String>, и я хочу написать функцию, которая использует эту последовательность строк, и ей не нужно владение над экземплярами Vec или String, должна ли эта функция принимать &[&str]? Если да, то какой лучший способ ссылаться на Vec<String> на &[&str]? Или это избыточное принуждение?

Ответ 1

Вы можете создать функцию, которая принимает как &[String], так и &[&str], используя AsRef trait:

fn test<T: AsRef<str>>(inp: &[T]) {
    for x in inp { print!("{} ", x.as_ref()) }
    println!("");
}

fn main() {
    let vref = vec!["Hello", "world!"];
    let vown = vec!["May the Force".to_owned(), "be with you.".to_owned()];
    test(&vref);
    test(&vown);
}

Ответ 2

Это фактически невозможно без выделения памяти 1.

Дело в том, что переход от String до &str - это не просто просмотр бит в другом свете; String и &str имеют разный макет памяти, и поэтому переход от одного к другому требует создания нового объекта. То же самое относится к Vec и &[]

Поэтому, хотя вы можете перейти от Vec<T> в &[T] и, следовательно, от Vec<String> до &[String], вы не можете напрямую перейти от Vec<String> в &[&str]:

  • либо принять, чтобы использовать &[String]
  • или выделите новый Vec<&str>, ссылающийся на первый Vec, и преобразуйте его в &[&str]

1 Требуемое преобразование невозможно, однако с использованием дженериков и привязки AsRef<str>, как показано в @aSpex, вы получите немного более подробное объявление функции с гибкостью, о которой вы просили.