1

When I have an Option and want a reference to what's inside or create something if it's a None I get an error.

Example Code:

fn main() {
    let my_opt: Option<String> = None;

    let ref_to_thing = match my_opt {
        Some(ref t) => t,
        None => &"new thing created".to_owned(),
    };

    println!("{:?}", ref_to_thing);
}

playground

Error:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:6:18
   |
6  |         None => &"new thing created".to_owned(),
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
   |                  |                            |
   |                  |                            temporary value dropped here while still borrowed
   |                  temporary value does not live long enough
...
10 | }
   | - temporary value needs to live until here

Basically the created value doesn't live long enough. What is the best way to get a reference to the value in a Some or create a value if it's a None and use the reference?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
sbditto85
  • 1,485
  • 14
  • 21

3 Answers3

6

You can also just write:

None => "new thing created"

With this adjustment your initial variant of the code will compile without the need of an extra variable binding.

An alternative could also be:

let ref_to_thing = my_opt.unwrap_or("new thing created".to_string());
ljedrz
  • 20,316
  • 4
  • 69
  • 97
  • Well my attempt to simplify my problem to an example failed. I wasn't using &str or String. In my original problem it was a &DatabaseConnection which wasn't easily solved that way as well as having the option be part of &mut of a struct which made things interesting. But yes for my example you are correct. – sbditto85 Sep 06 '18 at 04:30
  • Going to mark this as the correct answer as in my lame example it is. – sbditto85 Sep 06 '18 at 04:34
  • Worth noting that `unwrap_or` takes ownership of the Option which is not always possible. Like if the Option is owned by a struct and you only have an `&mut` of the struct. [unwrap_or](https://doc.rust-lang.org/std/option/enum.Option.html#method.unwrap_or) – sbditto85 Sep 06 '18 at 04:40
4

The only way I've found is to create a "dummy variable" to hold the created item and give it a lifetime:

fn main() {
    let my_opt: Option<String> = None;

    let value_holder;
    let ref_to_thing = match my_opt {
        Some(ref t) => t,
        None => {
            value_holder = "new thing created".to_owned();
            &value_holder
        }
    };

    println!("{:?}", ref_to_thing);
}

playground

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
sbditto85
  • 1,485
  • 14
  • 21
3

If you don't mind mutating your Option in place, you can use Option::method.get_or_insert_with:

fn main() {
    let mut my_opt: Option<String> = None;

    let ref_to_thing = my_opt.get_or_insert_with(|| "new thing created".to_owned());

    println!("{:?}", ref_to_thing);
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Interesting, learned something new. For my original problem that wouldn't work, but for the example I suppose it could. Thanks! – sbditto85 Sep 06 '18 at 04:32