Lifetime of variable in match pattern

This code will hang forever because it waits on a lock that is held already:

struct Foo {}

impl Foo {
    fn a(&mut self) -> Option<i32> {
        Some(0)
    }
    fn b(&mut self, i: i32) {}
}

fn main() {
    let foo = RwLock::new(Foo{});
    match foo.write().unwrap().a() {
        None => {}
        Some(i) => {
            foo.write().unwrap().b(i);
        }
    };
}

But if I write like this:

fn main() {
    let foo = RwLock::new(Foo{});
    let i = foo.write().unwrap().a();
    match i {
            None => {}
            Some(i) => {
                foo.write().unwrap().b(i);
            }
    }
}

The codes will work fine.

Shouldn't the lock release as soon as a() is called? I think the lock in the first case is temporary, but the fact is that it lives as long as b() get called.

So what's the difference between case 1 and case 2, is this a bug or design in purpose?

That is an intentional design. Rust keeps temporaries around until the end of the statement. Both let i and match i are equivalent in this case, but you see the problem because you do extra work inside the match.

If you try let i = (foo.write().unwrap().a(), foo.write().unwrap().a()) you'll also find it locked.

1 Like

I hope it can be smarter, because this design prevent me from using if let, which is more clean and elegant:

    if let Some(i) = foo.write().unwrap().a() {
            foo.write().unwrap().b(i);
    };

This interaction with if let is annoying indeed. You will have to use a temporary variable.

I don't think there are any plans so change this behaviour. Scope of temporaries is observable, so a fix for it could break code relying on the current behaviour.

3 Likes

There are other ways to get around this:

  • break-value -- loop { break foo.write().unwrap().a() }
  • IIFE -- (|| foo.write().unwrap().a())()
  • Result::map -- foo.write().map(|mut foo| foo.a()).unwrap()
    • without unwrap -- if let Ok(Some(i)) = foo.write().map(|mut foo| foo.a())
3 Likes

The important thing is to note that for the program to be correct compiler and developer have to agree on the scope.

But if developer thinks scope is small and compiler thinks it's large the end result is usually easily fixable compile-time error.

If developer thinks scope is large and it's, in reality, small, then this can lead to strange and dangerous problems without triggering compiler-time errors.

Thus I guess current scope rules are good even if I, too, suffer from them sometimes.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.