Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable does not live long enough: matching Option type

Tags:

rust

lifetime

I'm using getopts, and I was previously getting a value from a flag like this:

let file = matches.opt_str("f").unwrap();
let file_path = Path::new(&file);

But, I would like to handle the possible errors better, by making the path optional. This is my new code:

let file = matches.opt_str("f");
let file_path = match file {
    Some(f) => Some(Path::new(&f)),
    None    => None
}

But, when I try to compile this code, I get the error 'f' does not live long enough. I'm completely stumped.

Heres the MCVE of my code:

use std::path::Path;

fn main() {
    let foo = Some("success".to_string());
    let string = match foo {
        Some(s) => Some(Path::new(&s)),
        None    => None
    };
}
error[E0597]: `s` does not live long enough
 --> src/main.rs:6:35
  |
5 |     let string = match foo {
  |         ------ borrow later stored here
6 |         Some(s) => Some(Path::new(&s)),
  |                                   ^^ - `s` dropped here while still borrowed
  |                                   |
  |                                   borrowed value does not live long enough
like image 854
Alexis Dumas Avatar asked Sep 09 '15 18:09

Alexis Dumas


1 Answers

The issue arises because you are taking ownership of the contents of the Option in your match with the binding s (which uses bind-by-value). However, since nothing uses s after the match arm, it would be dropped and cause a invalid reference, so it's prevented.

Instead, you could bind-by-reference:

let string = match foo {
    Some(ref s) => Some(Path::new(s)),
    None        => None,
};

You could also get an Option<&T> from the Option<T> using as_ref:

let string = match foo.as_ref() {
    Some(s) => Some(Path::new(s)),
    None    => None,
};

I'd probably use the last solution coupled with map:

let string = foo.as_ref().map(Path::new);

In modern Rust, you can leverage match ergonomics and match on the &Option<T>:

let string = match &foo {
    Some(s) => Some(Path::new(s)),
    None    => None,
};

See also:

  • Why does pattern matching on &Option<T> yield something of type Some(&T)?
like image 79
Shepmaster Avatar answered Nov 15 '22 07:11

Shepmaster