In one of my online courses I demonstrate to students that move closures take ownership of the variables they capture, so they cannot be used outside the closure after the closure has been created, but an interesting typo uncovered a behavior I didn't expect:
let s = "🍓"; // oops, I meant to have .to_string() on that
let f = move || {
println!("{}", s);
};
f(); // prints 🍓
println!("{}", s); // unexpectedly works
Even though I forgot to create an actual String
with .to_string()
, I would have expected s
(the reference variable itself, not the static value it's pointing to) to have been moved into the closure. Why was it (apparently) not moved?
I verified that this seems to be true of immutable references in general, since this also works fine:
#[derive(Debug)]
struct Hello {}
fn main() {
let hello = Hello {};
let hello2 = &hello;
let f = move || {
println!("{:?}", hello2);
};
f();
println!("{:?}", hello2);
}
So...why does this work? Do immutable references implement Copy
(ie so the wide pointer itself gets copied under the hood)? Or is there some other reason that I'm not understanding?