rust

How to convert a Vec<String> to an array of string slices?


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]) {
    // ...
}

Solution

  • 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 &strs, this means that all these &strs must be stored contiguously.
    The Strings 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 &strs, we can pass them directly in a slice.
    But, as in your example, if we have contiguous Strings, 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" 
    */