This function doesn't compile because it tries to return v0
which has been moved where it's assigned to v1
. I understand that.
fn testvec() -> Vec<i64> {
let mut v0 = vec![0,1,2];
let v1 = v0;
//v0 = vec![1,2,3];
v0
}
But if I uncomment the v0
assignment, it compiles. What's the principle behind this? Is it documented?
When I first discovered this behavior, the function looked like this. It acts the same as above, but I also wonder if the nested block makes a difference.
fn testvec() -> Vec<i64> {
let mut v0 = vec![0,1,2];
{
let v1 = v0;
//v0 = vec![1,2,3];
}
v0
}
UPDATE
To summarize my confusion: I thought a "move" actually made the variable name inaccessible. But in reality only the contents of the variable become inaccessible. E.g. this compiler error is misleading: v0 moved here because
- it sounds like the variable name was moved instead of merely its value.
Think of
v0
andv1
as cardboard boxes which can contain one widget.With
let mut v0 = vec![0, 1, 2];
you create a cardboard box with the label “v0” written on its side in black marker a label saying “Contents: oneVec<i64>
” on its side, and put a widget labelled “[0, 1, 2]” in it. (The “mut” becomes a tacky sticker on the box saying that you’re allowed to fiddle with what’s stored in it, e.g. pushing a new element onto the vector, or throwing away the vector and putting a new one in its place.)With
let v1 = v0;
, you create another cardboard box, this one with the label “v1” (and another “Contents: oneVec<i64>
” label), and take the widget out of the “v0” box and put it in the “v1” box. (The v1 cardboard box, not having been declared withmut
, becomes a tacky sticker on the side of the box saying that you’re only allowed to take the widget out of the box, not to put anything else in it. “Not for reuse,” it reads. Maybe clamshell packaging would be a better analogy for such a thing. Just take care not to injure yourself with the scissors.)The v0 cardboard box does not now contain any widget, so the “Contents: one
Vec<i64>
” isn’t true—until it is true again, you can’t take anything out of the box or use the contents of the box, can you? If you ask for its contents, e.g. with specifyingv0
as the return value for the function, the compiler will yell at you because it knows that there won’t be a widget in the cardboard box.If you declared the v1 cardboard box inside a nested block, when you get to the end of that block you burninate the v1 cardboard box and anything inside it with your pocket flamethrower.
If you write
v0 = vec![1, 2, 3]
, you are creating a new widget with the label “[1, 2, 3]” on it and dropping it in the cardboard box labelled v0. The compiler, following the instruction sheet, can see that by the end of the function, the v0 cardboard box will always contain a widget, so it lets you return it as the value.Applying the analogy:
This is an instruction sheet that reads roughly like this:
This instruction sheet is called “testvec” and makes a
Vec<i64>
widget.Take a cardboard box and write “v0” on its side.
Make a
[0, 1, 2]
widget and drop it in the v0 box.Take a cardboard box and write “v1” on its side.
Take the
[0, 1, 2]
widget out of the v0 box and put it in the v1 box.Make a
[1, 2, 3]
widget and drop it in the (now empty) v0 box.Take the widget out of the v0 box: it’s the final product of this instruction sheet.
Oh, and we don’t need that v1 box any more, so burninate it and the widget that it contains.