Converting a tuple with String to tuple with &str (E0515)

I have a tuple of type (first: &str, second:String), and I need a tuple (first: &str, second:&str).

As a Rust newbie I of course did

t.map(|(first, second)| (first, second.as_str()))

but I got the error E0515 :slight_smile:

I've seen numerous explanations of the error and why this occurs, but in the answers I read I didn't see advices on how to best handle it to achieve the needed result.
Is there a standard approach to achieve what I want. How do I get a tuple of type (&str,&str) ?

I think you need to expand on your example a bit. E0515 happens when you try to return a reference to a local variable from a function, which will never work. Or when you are creating a temporary String in an expression that is dropped at the end of the statement (creating the same problem as trying to return a reference to a local from a function). Also, t.map(...) suggests to me that you don't have a single tuple, but an iterator of tuples that you try to convert. If you could provide us with a minimal reproducible example of your problem, preferably as a link to the playground, I'm sure we can help you find a better design that avoids E0515 :slightly_smiling_face:

2 Likes

In addition to what @jofas said, please just post the full error instead of the error number.

In general, when using a reference to a variable V, you need to ensure V is in scope. In both examples below, x is in scope when &x is used, and t is in scope when &t.1 is used.

let x = "x".to_string();
{
    let t: (&str, String) = (&x, "y".to_string());
    {
        let u: (&str, &str) = (t.0, &t.1);
    }
}
let x = "x".to_string();
let t: (&str, String) = (&x, "y".to_string());
let u: (&str, &str) = (t.0, &t.1);

Thanks for your fast reactions @jofas and @jumpnbrownweasel .
I created a toy example representing the situation at Rust Playground

The code is very short so I can post it here too I guess:

fn work_on_tuple() {
    let s1= "s1";
    let s2="ss2";
    let r =
        Some((s1,s2))
        .map(|(fst,snd)| (fst,snd.replacen("s","",1).as_str()));   // <------------------ error line

    consumer(r);

}

fn consumer(t:Option<(&str,&str)>) {
    println!("tuple {:?}", t);
}
2 Likes

You need to let the String be owned by some variable. You can do that by using r as the variable:

fn work_on_tuple() {
    let s1 = "s1";
    let s2 = "ss2";
    // this has an `(&str, String)`
    let r = Some((s1, s2)).map(|(fst, snd)| (fst, snd.replacen("s", "", 1)));
    
    // then convert to `(&str, &str)` for use
    consumer(r.as_ref().map(|&(fst, ref snd)| (fst, snd.as_str())));
}
3 Likes

Thanks @kpreid !
I've made the working code also available at the Rust Playground

@kpreid showed how to declare the owned String in the scope of the next expression that takes a reference to that String. This kind of thing is often needed, and it is the important thing to learn here.

It is also possible, in some cases, to reference the String as a temporary value in a single expression. That works in this case as follows, but isn't always possible in my experience:

    consumer(
        Some((s1, s2))
            .map(|(fst, snd)| (fst, snd.replacen("s", "", 1)))
            .as_ref()
            .map(|&(fst, ref snd)| (fst, snd.as_str())),
    );

playground

2 Likes

A good reference for temporaries and how they work in different language constructs and control flows is Mara Bos' introduction to super let IMO:

4 Likes

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.