-1

I expect the following code to compile and print Foo(6) as the value of b, owning the reference to a is dropped after the match block.

It seems related to this compiler error:

error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
  --> src/main.rs:26:22
   |
13 |     let b = get_foo(&mut a);
   |                          - mutable borrow occurs here
...
26 |     println!("{:?}", a);
   |                      ^ immutable borrow occurs here
27 | }
   | - mutable borrow ends here

Dropping the value of b doesn't work either, because it is partially moved:

error[E0382]: use of partially moved value: `b`
  --> src/main.rs:24:10
   |
18 |         Some(value) => *value = y,
   |              ----- value moved here
...
24 |     drop(b);
   |          ^ value used here after move
   |
   = note: move occurs because `(b:std::prelude::v1::Some).0` has type `&mut u32`, which does not implement the `Copy` trait

Is there a better way to fix this rather than putting lines let b and match b into an inner block? That just looks weird and ugly.

Shouldn't the compiler understand that the reference is dropped, and be able to compile that code?

#[derive(Debug)]
struct Foo(u32);

fn get_foo(bar: &mut Foo) -> Option<&mut u32> {
    Some(&mut bar.0)
}

pub fn test() {
    let mut x = 5;
    let mut y = 6;
    let mut a = Foo(x);

    // {
    
    let b = get_foo(&mut a);

    match b {
        Some(value) => *value = y,
        _ => (),
    }
    
    // }

    //    drop(b);

    println!("{:?}", a);
}
mcarton
  • 27,633
  • 5
  • 85
  • 95
Ákos Vandra-Meyer
  • 1,890
  • 1
  • 23
  • 40

1 Answers1

4

Is there a better way to fix this

Yes, but not in stable Rust. You need non-lexical lifetimes:

#![feature(nll)]

#[derive(Debug)]
struct Foo(u32);

fn get_foo(bar: &mut Foo) -> Option<&mut u32> {
    Some(&mut bar.0)
}

pub fn test() {
    let x = 5;
    let y = 6;
    let mut a = Foo(x);

    let b = get_foo(&mut a);

    if let Some(value) = b {
        *value = y;
    }

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

fn main() {}

Until then, just use the extra block.

Dropping the value of b doesn't work either

drop has nothing to do with borrows.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Why would the drop have nothing to do with this? As far as I understand, the compiler is complaining that `b` is/might be holding a reference for `a`. Dropping `b` should take care of that, shouldn't it? NLL takes care of it, I should read up on what it exactly is, but I'm interested in the issue with drop as well. – Ákos Vandra-Meyer Mar 27 '18 at 06:21
  • @ÁkosVandra if there something you don't understand from the first question I linked to ([Moved variable still borrowing after calling `drop`?](https://stackoverflow.com/q/43428894/155423)), perhaps adding comments to it would be more appropriate. – Shepmaster Mar 27 '18 at 12:01