Assigning to a moved variable seems to “negate” th

2019-08-15 04:32发布

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.

标签: rust
1条回答
Luminary・发光体
2楼-- · 2019-08-15 05:08

Think of v0 and v1 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: one Vec<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: one Vec<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 with mut, 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 specifying v0 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:

fn testvec() -> Vec<i64> {
    let mut v0 = vec![0,1,2];
    let v1 = v0;
    v0 = vec![1,2,3];
    v0
}

This is an instruction sheet that reads roughly like this:

  1. This instruction sheet is called “testvec” and makes a Vec<i64> widget.

  2. Take a cardboard box and write “v0” on its side.

    Make a [0, 1, 2] widget and drop it in the v0 box.

  3. 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.

  4. Make a [1, 2, 3] widget and drop it in the (now empty) v0 box.

  5. 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.

查看更多
登录 后发表回答