From Vec<impl ToString> to Vec<&str>

Hi there.
Say I have a variable headers: Vec<(Variant, Variant)> (where Variant implements ToString) which I want to turn into a Vec<(&str, &str)>. What's the best way to do this? Currently, this is compiling:

let h1: Vec<(String, String)> = headers.iter()
    .map(|(key, val)| {
        (key.to_string(), val.to_string())
    }).collect();
let h2: Vec<(&str, &str)>= h1.iter()
    .map(|(key, val)| {
        (key.as_str(), val.as_str())
    })
    .collect();

Is there a solution where you only need to iterate over the Vec once? I'm getting borrow checker errors complaining that Strings returned by .to_string() do not live long enough that we may be able to return them as &str's. I understand the error, but am not sure how to fix it.

There isn't really much way to fix it, you're probably better off just using Vec<(String, String)> instead. Is there some other context for why that wouldn't work?

I'm calling a function that takes in a Vec<(&str, &str)>

In that case, the snippet you gave is probably the best answer. Unless Variant holds a String itself, in which case you can do

let h: Vec<(&str, &str)> = headers.iter()
    .map(|(key, val)| {
        // where instead of `.my_string()`, whatever function you use to get them
        (&*key.my_string(), &*val.my_string()) 
    }).collect();

Unless Variant holds a String itself

Unfortunately it doesn't :frowning:

Is there really no way to do this in one iteration?

As far as I'm aware, no. The created Strings have to be stored somewhere before the &strs can reference them

2 Likes

You can pre-allocate your storage.

    let mut temp_storage = vec![(String::new(), String::new()); header.len()];
    let args = header
        .iter()
        .zip(temp_storage.iter_mut())
        .map(|(header, storage)| {
            storage.0 = header.0.to_string();
            storage.1 = header.1.to_string();
            (storage.0.as_ref(), storage.1.as_ref())
        })
        .collect();
4 Likes

Can you make your Variant implement AsRef<str>?

Otherwise there's no cheap way. ToString doesn't promise that the string exists in memory — it can be dynamically generated on the fly. OTOH &str promises that it already exists in memory.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.