Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"cannot infer an appropriate lifetime for pattern due to conflicting requirements" in `ref mut` pattern

Tags:

rust

lifetime

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.

like image 219
Lukas Kalbertodt Avatar asked Feb 22 '17 16:02

Lukas Kalbertodt


1 Answers

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)

like image 154
Chris Emerson Avatar answered Sep 20 '22 14:09

Chris Emerson