rustrust-macros

Idiomatic way to circumvent "temporary value dropped while borrowed"?


Problem

I often run into the old temporary value dropped while borrowed-Error in Rust when working with iterators, espcially when ones over &str or String. Alternatively this happens when I read from some file. You can usually just fix the problem by defining a var to own the temporary value: Example:

fn main() {
    let s = Some("a".to_string());

    let s: &str = s.unwrap().as_str();

    dbg!(s);
}

Throws the error since no var owns the String from the unwrap. Simple solution would be:

fn main() {
    let s = Some("a".to_string());

    let temp: String = s.unwrap()
    let s: &str = temp.as_str();

    dbg!(s);
}

Idiomatic Solution (Not possible)

This however annoys me. This situation is relatively unrealistic, but when working with iters you do get this problem. When you run into this, you have to break your entire iterator chain just to save a temporary value. In my eyes a less verbose way to write this code would be:

fn main() {
    let s = Some("a".to_string());

    let s: &str = s.unwrap().define!().as_str();

    dbg!(s);
}

This uses the imaginary macro define!. This macro would in theory work as a sort of method-macro, which takes the type to the left of the period as an argument

Current solution (Maybe?)

It would sort of look like this when rephrased to the the current macro syntax:

let s: &str = define!(s.unwrap()).as_str();

This macro would maybe be possible with current macro types, although I'm not a macro expert. Both these macros could expand to something like this

let __temp_s = s.unwrap();
let s: &str = __temp_s.as_str();

It might still be problematic as this would have to fit after the let s: &str =-Part since it can't expand outside of its call-site.

Honestly I just want to get rid of the minor inconvenience of defining a new var in the middle of me doing something else (Or having to go to the start of the expression to call a macro on the whole expression). This is just some everyday compiler-fighting im dealing with. I would be very much intrested to hear if you have any ideas on how to this in current rust (or if my problem even makes sense)!


Solution

  • In general, you do just have to create a temporary variable if you're going to move out of a variable and then take a reference to the result. But in this case there is let s = s.as_deref().unwrap();, which switches the order of reference-taking and unwrapping so that you don't rely on the owned-but-temporary result of unwrapping.