分配给移动的变量似乎"否定"了这一举措

Kel*_*vin 1 rust

此函数无法编译,因为它尝试返回v0已分配到的位置v1.我明白那个.

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

但如果我取消对v0作业的注释,它就会编译.这背后的原理是什么?有记录吗?

当我第一次发现这种行为时,函数看起来像这样.它的行为与上面相同,但我也想知道嵌套块是否有所不同.

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

UPDATE

总结一下我的困惑:我认为"移动"实际上使变量名称无法访问.但实际上只有变量的内容变得无法访问.例如,这个编译器错误具有误导性:v0 moved here because- 听起来变量名称被移动而不仅仅是它的值.

Chr*_*gan 7

想想v0v1作为可以包含一个小部件的纸板箱.

随着let mut v0 = vec![0, 1, 2];你创建一个标签为"v0"的纸板箱,其侧面用黑色标记写着一个标签,上面写着"内容:一个Vec<i64>",并在其中放置一个标有"[0,1,2]"的小部件.("mut"在盒子上变成了一个俗气的贴纸,说你可以摆弄它中存储的东西,例如将一个新元素推到矢量上,或丢弃矢量并将一个新元素放在它的位置.)

使用let v1 = v0;,您创建另一个纸板箱,这个纸板箱带有标签"v1"(以及另一个"内容:一个Vec<i64>"标签),并将小部件从"v0"框中取出并放入"v1"框中.(没有声明的v1纸板盒mut在盒子的侧面变成了一个俗气的贴纸,说你只允许从盒子里拿出小部件,而不是把任何东西放在盒子里."不能重复使用"它说明了.也许翻盖式包装对于这样的事情来说是一个更好的比喻.注意不要用剪刀伤害自己."

v0纸板盒现在不包含任何小部件,因此"内容:一个Vec<i64>"不是真的 - 直到它再次成立,你不能开箱即用或使用盒子的内容,是吗?如果你要求它的内容,例如指定v0为函数的返回值,编译器会对你大喊大叫,因为它知道纸板盒中不会有小部件.

如果您在嵌套块中声明了v1纸板盒,当您到达该块的末尾时,您将使用口袋喷火器对v1纸板盒及其内部的任何物品进行刻录.

如果你写v0 = vec![1, 2, 3],你正在创建一个标签为"[1,2,3]"的新小部件,并将其放在标有v0的纸板箱中.编译器遵循说明书,可以看到在函数结束时,v0纸板盒将始终包含一个小部件,因此它允许您将其作为值返回.


应用类比:

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

这是一个大致如下所示的说明书:

  1. 该说明书称为"testvec"并制作一个Vec<i64>小部件.

  2. 拿一个纸板箱,边写"v0".

    制作一个[0, 1, 2]小部件并将其放在v0框中.

  3. 拿一个纸板箱,边写上"v1".

    [0, 1, 2]小部件从v0框中取出并放入v1框中.

  4. 制作一个[1, 2, 3]小部件并将其放入(现在为空)v0框中.

  5. 将小部件从v0框中取出:它是本说明书的最终产品.

    哦,我们不再需要那个v1盒了,所以要烧掉它和它包含的小部件.