为什么编译器不抱怨迭代器移动到for循环是不可变的?

时间:2017-12-11 19:28:22

标签: rust move-semantics

我正在阅读Rust Book的第二版,我在迭代器部分找到了以下示例:

let v1 = vec![1, 2, 3];
let v1_iter = v1.iter();    
for val in v1_iter {
    println!("Got: {}", val);
}

为什么编译器不抱怨v1_iter是不可变的?该书说for循环取得了v1_iter的所有权并使其在幕后变得可变,但是你能将一个不可变变量转换为可变变量吗?

1 个答案:

答案 0 :(得分:12)

  

这本书说for循环取得了v1_iter的所有权,并使其在幕后变得可变,

确切地说,人们可以做一个更简单的例子:

let v = vec![1,2,3];
let mut x = v;
x.push(0);

请注意vx是单独的变量绑定:只要变量v保留了我们的3元素向量,变量的约定就是向量不会变异。但是,向量被移动到x,这表明可变性是可以接受的。这同样适用于函数调用:

fn foo(mut x: Vec<i32>) {
    x.push(0);
}

let v = vec![1,2,3];
foo(v);

这是安全的,因为只有一个变量在其生命周期的任何一点拥有该向量。将v移至x后,将无法再使用v。同样,在您的代码中,for循环后无法再使用v1_iter

  

但是你可以将一个不可变的变量转换成可变的吗?

两个片段都有效,因为该值已移至声明为mut的新变量。但是,一旦变量被声明为不可变(或可变),该变量在其所有生命周期内都保持不变,并且无法更改。所以答案是否定的,但是所有权语义允许在具有不同可变性保证的变量之间移动值。

另见: