Is the moved variable still being borrowed after the call to `drop`?

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 seen from the error in the commented code), but still thinks that the variable is borrowing from a

! This is not fair!

If this is to be seen as one of rust-lang / rust # 6393 's many hoaxes (which is now being tracked by rust-lang / rfcs # 811 ?), The discussion there seems to be focused on what &mut self

both &self

coexist in the same block.

+3


source to share


2 answers


I cannot give you a definite answer, but I will try to explain a few things here. Start by clarifying:

The compiler knows drop()

dropsx

This is not true. Although there are a few "magic" things in the standard library that the compiler knows about, drop()

there is no such element of lang. In fact, you can implement it drop()

yourself and this is actually the simplest task:

fn drop<T>(_: T) {}

      

The function just takes something by value (so it moved to drop()

), and since nothing happens internally drop()

, that value is discarded at the end of the scope just like any other function. So: the compiler doesn't know what is being x

dropped, it just knows what is being x

moved.


As you may have noticed, the compiler error remains the same regardless of whether we add a call drop()

. Right now, the compiler will only consider the scope of a variable when it comes to references. From Niko Matsakis's introduction to NLL :

The way the compiler works by assigning a reference to a variable means that its lifetime must be as large as the entire scope of that variable.



And in a later blog post :

In particular, today, when the lifespan must extend beyond a single statement [...], it must fully extend to the end of the closing block.

This is exactly what is happening here, so yes, your problem is with all this "lexical borrowing". From the point of view of modern compilers, the lifetime of an expression &a

should be at least equal to the size x

. But that won't work as the link will survive a

since the scope is x

larger than the scope a

as indicated by the compiler:

= note: values in a scope are dropped in the opposite order they are created

      

And I think you already know all this, but you can fix your example by replacing the lines let mut x ...;

and let a ...;

.


I'm not sure if this exact problem will be solved by any of the currently suggested solutions. But I hope we get to see this soon enough as this is all covered in the Rust 2017 roadmap. A good place to read updates is here (which also contains links to five relevant entries on Niko's blog).

+7


source


The compiler knows drop()

drops x

(as you can see from the error in the code with comments)

The Rust compiler knows nothing about drop

and what it does. It's just a library function that can do whatever it likes with the value since it now belongs to it.

The definition drop

, as the documentation points out, is literally fair:

fn drop<T>(_x: T) { }

      



This works because the argument is moved to the function and is therefore automatically discarded by the compiler when the function ends.

If you create your own function, you get exactly the same error message:

fn my_drop<T>(_x: T) { }

fn main() {
    let mut x: Vec<&i32> = vec![];
    let a = 1;
    x.push(&a);
    my_drop(x);
    x.len();
}

      

This is exactly what the documentation saysdrop

when he says "is not magic . "

+5


source







All Articles