5

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
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Alexis Dumas
  • 1,299
  • 11
  • 30

1 Answers1

8

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:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • I'd use [`PathBuf::from()`](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#impl-From%3CString%3E) instead of `Path`. – Chayim Friedman Dec 23 '21 at 07:08