I have a Vec<String>
and I would like to call a function that receives a &[&str]
parameter, but I don't know how to convert one into the other.
For instance, how would call the mix_colours
function in the following code?
fn main() {
let colours: Vec<String> = vec!["blue".to_string(), "red".to_string(), "yellow".to_string()];
}
fn mix_colours(strings: &[&str]) {
// ...
}
Although Vec
can decay to &[]
and String
can decay to &str
, we cannot perform these two decays in one step.
Since, in the end, we want a slice of &str
s, this means that all these &str
s must be stored contiguously.
The String
s are contiguous in the Vec
but taking a &str
from each of them just produces temporaries which are never stored together.
Then, we need to allocate a storage for them: a new Vec
in this example.
If we don't want to allocate this new storage, we can change the parameter to &[impl AsRef<str>]
: a slice of anything that can provide a reference to str
.
This way, if we already have some contiguous &str
s, we can pass them directly in a slice.
But, as in your example, if we have contiguous String
s, we can also pass them directly in a slice, because each of them will be asked .as_ref()
inside the function.
(see mix_colours_bis()
)
fn main() {
let colours: Vec<String> =
vec!["blue".to_string(), "red".to_string(), "yellow".to_string()];
let slice_of_colours: &[String] = colours.as_slice();
// mix_colours(slice_of_colours); // impossible, &[String] is not &[&str]
// we need a contiguous storage for many &str,
// so that we can take a slice on all of them.
let vec_of_str_colours: Vec<&str> =
colours.iter().map(|c| c.as_str()).collect();
let slice_of_str_colours: &[&str] = vec_of_str_colours.as_slice();
mix_colours(slice_of_str_colours);
mix_colours_bis(slice_of_colours);
mix_colours_bis(slice_of_str_colours);
}
fn mix_colours(strings: &[&str]) {
for s in strings.iter() {
print!("{:?} ", s);
}
println!();
}
fn mix_colours_bis(strings: &[impl AsRef<str>]) {
for s in strings.iter() {
let r = s.as_ref(); // the only thing we know about s
print!("{:?} ", r);
}
println!();
}
/*
"blue" "red" "yellow"
"blue" "red" "yellow"
"blue" "red" "yellow"
*/