Convert Vec<String> into a slice of &str in Rust?
Solution 1
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);
}
Solution 2
This is actually impossible without either memory allocation or per-element call1.
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 firstVec
, 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);
}
1 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, but you do have to call .as_ref()
in all elements.
Don Rowe
Updated on July 12, 2022Comments
-
Don Rowe almost 2 years
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 aString
. Similarly, it's recommended to use references to slices (&[]
) instead ofVec
s unless you really need ownership over theVec
.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 theVec
orString
instances, should that function take&[&str]
? If so, what's the best way to reference theVec<String>
into&[&str]
? Or, is this coercion overkill? -
Don Rowe over 7 yearsThanks, Matthieu. For my case right now, I think I'll go with
&[String]
since I imagine allocating a newVec<&str>
incurs extra work. -
Matthieu M. over 7 years@DonRowe: It incurs an extra allocation (O(1) but potentially expensive) + conversion (O(n)).
-
user4815162342 over 7 yearsI think this is the answer the OP was looking for, as it allows using the slice without an unnecessary allocation. This approach is even more useful when accepting a slice of
AsRef<Path>
- you want the function to accept all of&[&str]
,&[String]
,&[Path]
, and&[PathBuf]
, without allocating new memory. -
klefevre over 5 yearsOne sad thing is if you're trying to take a
Option<&[T]>
you can't just pass aNone
without specifying a concret type