8
struct RefWrap<'a> {
    wrap: &'a mut Option<String>,
}

impl<'a> RefWrap<'a> {
    fn unwrap(&mut self) -> &'a mut String {
        match *self.wrap {
            Some(ref mut s) => s,
            None => panic!(),
        }
    }
}

(Playground)

As far as I understand, this code is correct (the returned reference really has the lifetime 'a. But Rust produces the following error:

error[E0495]: cannot infer an appropriate lifetime for pattern due to conflicting requirements
 --> <anon>:8:18
  |
8 |             Some(ref mut s) => s,
  |                  ^^^^^^^^^

Using immutable references, it works without an error.

There has been one similar question, but I'm pretty sure it's not helpful in this case.

Community
  • 1
  • 1
Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305

1 Answers1

6

It looks like the conflict is that the return value:

  • Must be valid for at least the lifetime 'a
  • Must not outlive &mut self, which is only the lifetime of the function call.

If this were allowed, it would let you call it twice and get two &'a mut references to the same String contents:

let mut w = RefWrap { wrap: &mut s };
let ref1 = w.unwrap();
let ref2 = w.unwrap();  // two mutable references!

The reason is that the way Rust reasons about whether something is borrowed is by tying lifetimes together - but here you are explicitly saying that the return value's lifetime is unrelated to &mut self, which means it doesn't extend the borrow - and then you can borrow again with another call.

The solution here, to get the original reference lifetime out without risking a second &mut reference overlapping it, is to take self by value (move) so that it can't be used again. The compiler is happy with this:

impl<'a> RefWrap<'a> {
    fn unwrap(self) -> &'a mut String {
        match *self.wrap {
            Some(ref mut s) => s,
            None => panic!(),
        }
    }
}

(Playground)

Chris Emerson
  • 13,041
  • 3
  • 44
  • 66
  • "*it would let you call it twice and get two `&'a mut` references*" -> I don't think so. For example, look at [this code](https://play.rust-lang.org/?gist=e1fa7f12abeb7255bac4deaed23a2ce0&version=stable&backtrace=0). I used `transmute()` to make the method work, but I still can't create two mutable references. Also: I specifically want the returned reference to have the "longer" lifetime, namely `'a`. – Lukas Kalbertodt Feb 22 '17 at 16:41
  • 5
    Yes you can: https://play.rust-lang.org/?gist=819f30fafa65066e9f9d8c766cf17106&version=stable&backtrace=0 – Chris Emerson Feb 22 '17 at 16:48