fn main() {
let mut x: Vec<&i32> = vec![];
let a = 1;
x.push(&a);
drop(x);
// x.len(); // error[E0382]: use of moved value: `x`
} // `a` dropped here while still borrowed
The compiler knows drop()
drops x
(as evident from the error in the commented-out code) but still thinks the variable is borrowing from a
! This is unfair!
Should this be considered as one of numerous dupes of rust-lang/rust#6393 (which is now tracked by rust-lang/rfcs#811?) But the discussion there seems to be centered on making &mut self
and &self
coexist in a single block.
The Rust compiler doesn't know anything about
drop
and what it does. It's just a library function, which could do anything it likes with the value since it now owns it.The definition of
drop
, as the documentation points out, is literally just:It works because it the argument is moved into the function, and is therefore automatically dropped by the compiler when the function finishes.
If you create your own function, you will get exactly the same error message:
This is exactly what is meant in the documentation when it says
drop
"isn't magic".I can't give you a definite answer, but I'll try to explain a few things here. Let's start with clarifying something:
This is not true. While there are a few "magic" things in the standard library that the compiler knows about,
drop()
is not such a lang item. In fact, you could implementdrop()
yourself and it's actually the easiest thing to do:The function just takes something by value (thus, it's moved into
drop()
) and since nothing happens inside ofdrop()
, this value is dropped at the end of the scope, like in any other function. So: the compiler doesn't knowx
is dropped, it just knowsx
is moved.As you might have noticed, the compiler error stays the same regardless of whether or not we add the
drop()
call. Right now, the compiler will only look at the scope of a variable when it comes to references. From Niko Matsakis' intro to NLL:And in a later blog post of his:
This is exactly what happens here, so yes, your problem has to do with all this "lexical borrowing" stuff. From the current compilers perspective, the lifetime of the expression
&a
needs to be at least as large as the scope ofx
. But this doesn't work, since the reference would outlivea
, since the scope ofx
is larger than the scope ofa
as pointed out by the compiler:And I guess you already know all that, but you can fix your example by swapping the lines
let mut x ...;
andlet a ...;
.I'm not sure whether or not this exact problem would be solved by any of the currently proposed solutions. But I hope that we will see soon enough, as all of this is being addressed as part of the Rust 2017 roadmap. A good place to read up on the updates is here (which also contains links to the five relevant blog posts of Niko).