Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert Vec<String> into a slice of &str in Rust?

Per Steve Klabnik's writeup in the pre-Rust 1.0 documentation on the difference between String and &str, in Rust you should use &str unless you really need to have ownership over a String. Similarly, it's recommended to use references to slices (&[]) instead of Vecs unless you really need ownership over the Vec.

I have a Vec<String> and I want to write a function that uses this sequence of strings and it doesn't need ownership over the Vec or String instances, should that function take &[&str]? If so, what's the best way to reference the Vec<String> into &[&str]? Or, is this coercion overkill?

like image 273
Don Rowe Avatar asked Dec 16 '16 07:12

Don Rowe


2 Answers

You can create a function that accepts both &[String] and &[&str] using the 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); } 
like image 199
aSpex Avatar answered Sep 20 '22 01:09

aSpex


This is actually impossible without memory allocation1.

Going from String to &str is not just viewing the bits in a different light; String and &str have a different memory layout, and thus going from one to the other requires creating a new object. The same applies to Vec and &[]

Therefore, whilst you can go from Vec<T> to &[T], and thus from Vec<String> to &[String], you cannot directly go from Vec<String> to &[&str]. Your choices are:

  • either accept &[String]
  • allocate a new Vec<&str> referencing the first Vec, and convert that into a &[&str]

As an example of the allocation:

fn usage(_: &[&str]) {}  fn main() {     let owned = vec![String::new()];      let half_owned: Vec<_> = owned.iter().map(String::as_str).collect();      usage(&half_owned); } 

1The conversion required is impossible, however using generics and the AsRef<str> bound as shown in @aSpex's answer you get a slightly more verbose function declaration with the flexibility you were asking for.

like image 33
Matthieu M. Avatar answered Sep 22 '22 01:09

Matthieu M.