此函数无法编译,因为它尝试返回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- 听起来变量名称被移动而不仅仅是它的值.
想想v0和v1作为可以包含一个小部件的纸板箱.
随着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)
这是一个大致如下所示的说明书:
该说明书称为"testvec"并制作一个Vec<i64>小部件.
拿一个纸板箱,边写"v0".
制作一个[0, 1, 2]小部件并将其放在v0框中.
拿一个纸板箱,边写上"v1".
将[0, 1, 2]小部件从v0框中取出并放入v1框中.
制作一个[1, 2, 3]小部件并将其放入(现在为空)v0框中.
将小部件从v0框中取出:它是本说明书的最终产品.
哦,我们不再需要那个v1盒了,所以要烧掉它和它包含的小部件.