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 Vec
s 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?
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); }
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:
&[String]
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With