Moving out of `if let` scope

Here's what I'm trying to do:

    let mut v = Vec::<&str>::new();
    let opt = Some("foo".to_string());

    if let Some(s) = opt {
        v.push(s.as_str());
    }        // `s` dropped here while still borrowed
    dbg!(v); // borrow later used here

As I understand it, the issue occurs because value I'm trying to put into the container has shorter lifetime than the container itself. So I can move it into the outer scope:

    let unscopped;
    if let Some(s) = opt {
        unscopped = s;
        v.push(unscopped.as_str());
    }
    dbg!(v);

It works, but it feels too verbose. What would be an ergonomic way of doing this?

You can use Option::as_ref like this:

if let Some(s) = opt.as_ref() {
    v.push(s.as_str());
}

or match on &opt like this:

if let Some(s) = &opt {
    v.push(s.as_str());
}

In more complicated cases, you might want to use the ref keyword to specify which bindings should be by-reference:

if let Some(ref s) = opt {
    v.push(s.as_str());
}

For this specific case, you can also use Option::as_deref, which combines the as_ref and as_str operations, converting &Option<String> into Option<&str> in a single call:

if let Some(s) = opt.as_deref() {
    v.push(s);
}
6 Likes

Thank you, as_ref happens to work even without explicit as_str:

if let Some(s) = opt.as_ref() {
    v.push(s);
}