The following code fails to compile:
use std::thread;
#[derive(Debug)]
struct Contained {
a: u8
}
#[derive(Debug)]
struct Wrapper<'a> {
b: &'a Contained,
}
fn main() {
println!("Hello, world!");
let c = Contained { a: 42 };
let w = Wrapper { b: &c };
println!("C: {:?}", c);
println!("W: {:?}", w);
let handle = thread::spawn(move || {
println!("C in thread: {:?}", c);
});
handle.join().unwrap();
}
Error message:
src/main.rs:24:39: 24:40 error: cannot move `c` into closure because it is borrowed [E0504]
src/main.rs:24 println!("C in thread: {:?}", c);
^
<std macros>:2:25: 2:56 note: in this expansion of format_args!
<std macros>:3:1: 3:54 note: in this expansion of print! (defined in <std macros>)
src/main.rs:24:9: 24:42 note: in this expansion of println! (defined in <std macros>)
src/main.rs:18:27: 18:28 note: borrow of `c` occurs here
src/main.rs:18 let w = Wrapper { b: &c };
^
The borrow checker is obviously right about this. A way to work around this is by using explicit scopes, so that the wrapper is dropped, freeing the borrowed contained object.
let c = Contained { a: 42 };
{
let w = Wrapper { b: &c };
println!("C: {:?}", c);
println!("W: {:?}", w);
}
let handle = thread::spawn(move || {
println!("C in thread: {:?}", c);
});
This compiles properly.
Another way to make an object go out of scope is by using the std::mem::drop
function. In this case it does not work though:
let c = Contained { a: 42 };
let w = Wrapper { b: &c };
println!("C: {:?}", c);
println!("W: {:?}", w);
drop(w);
let handle = thread::spawn(move || {
println!("C in thread: {:?}", c);
});
The borrow checker complains with the same error message as before.
Why does drop(w)
not free the borrowed c
?