The compiler prefers to capture a closed-over variable by immutable borrow, followed by unique immutable borrow (see below), by mutable borrow, and finally by move. It will pick the first choice of these that allows the closure to compile.
While, the following fn a() does not compiles, seems compiler prefer using mutable borrow instread of move. That is conflict with document: it will pick the first choice of these that allows the closure to compile.
While, if I use another let uu = uc; in fn b() then compiler will use move.
I don't know why fn a() can't compiles just like fn b().
#[test]
fn a() {
let mut uc = UnsafeCell::new(9);
let j = thread::spawn(|| {
*uc.get_mut() = 100;
});
j.join();
}
#[test]
fn b() {
use std::cell::UnsafeCell;
let mut uc = UnsafeCell::new(9);
let j = thread::spawn(|| {
let mut uu = uc;
*uu.get_mut() = 100;
});
j.join();
}
The choice is made only with regards to the contents of the closure expression; the compiler does not take into account surrounding code, such as the lifetimes of involved variables.
so this is not actually in conflict. The compiler looks at how the captured variables are used in the closure's body and decides on a capture mode based on that. In this case uc.get_mut() is just a mutable use of uc, so that's what you get.
The reason this is done is that lifetime requirements are checked later in the compilation process, and type inference (which includes closure type inference) runs before that.