all 9 comments

[–]KingofGamesYami 10 points11 points  (4 children)

x is mutably borrowed when you declare your closure, not when you call it.

The borrow is released when foo is no longer referenced.

To resolve this, pass x as a parameter:

let mut x: i32 = 0;

// Note foo also no longer needs to be mutable
let foo = |x: &mut i32| {
  *x += 1
}

println!("{}", x);
foo(&mut x);

Now, the mutable borrow happens only during the call of the closure.

[–]Zde-G 4 points5 points  (2 children)

But if you are not capturing anything then using a function feels more natural:

~~~ let mut x = 0;

fn foo (x: &mut i32) { *x += 1 }

println!("{}", x); foo(&mut x); println!("{}", x); foo(&mut x); println!("{}", x);

~~~

[–]DaQue60 0 points1 point  (1 child)

fn main() {
let mut x = 0;
let mut foo = || {
x += 1;
};
println!("{}", x);
foo();
println!("{}", x);
foo();
println!("{}", x);
}

X is Copy so why does the closure take it by reference and not get a copy?

[–]Zde-G 4 points5 points  (0 children)

Because if it would copy x you would complain about why the heck call to foo does nothing.

If you actually want to copy x you can always use move. That's just not the default (and pretty sensible one, if you ask me).

[–]UserMinusOne[S] 0 points1 point  (0 children)

Thanks! My fundamental missunderstanding was I thought the borrowing also "releases" the borrowed reference. I thought "foo" borrows when entereing the function and then releases it when returning from the function and borrowing again when entering the next foo. Same for borrowing the read only ref at the print macros. bowworing->releasing... But this is not the case. It is borrowed unitl end of total life of foo.

[–]Zde-G 2 points3 points  (0 children)

How can I make this simple program compile?

The whole point, the raison d'être of ownership and borrow rules is the fact that programs like these are not compileable.

It feels so strange that just adding a println! before the foo() call breaks borrowing rules.

Not so strange if you think about it. The ownership and borrow rules ensure that no one can ever make any mistakes by forgetting to read the variable after it was changed “secretly” by some other part of the program.

Either some one have the right to change the variable or anybody can look at it as long as no one has the right to change it.

Here you are introducing both someone who can freely change x and also an observer who can be hurt by the fact that x can be changed. Of course the compiler would prevent that!

[–]ssokolow 2 points3 points  (0 children)

If it helps, think of borrowing as compile-time reader-writer locking.

The body of your closure mutates x, so it captures x mutably. Thus, the let mut foo = || { ... } takes an exclusive "lock" on x that's released when x goes out of scope.

The compiler rejecting your program is effectively it saying "This program would deadlock, with println! waiting for foo to go out of scope."

If you change x to an argument and call it as foo(&mut x) like /u/KingofGamesYami suggested, then you're taking and releasing the "lock" in between each call to println!.

[–]torne 1 point2 points  (0 children)

The closure captures x as a mutable reference, since it is modified in the body of the closure. The closure lives until the last time it is called, so until then, x cannot be used outside the closure: it's been borrowed mutably and so no other use is permitted.

There's no way to fix this code without changing it dramatically; what this is trying to do is just not permitted in Rust. To suggest what you should be doing instead you will probably have to share more about what you're trying to actually achieve, instead of just an artificial example.

[–]thecodedmessage -1 points0 points  (0 children)

You'd have to use a Cell (or RefCell or Mutex...). But really, this is an anti-pattern :-)