为什么for循环绑定上的`ref mut`与要循环遍历的变量上的`&mut`不同?

时间:2018-12-05 11:43:58

标签: rust

Rust by Example中,它说:

  

在作业左侧借用ref相当于在右侧借用&

我认为这两个for循环将是等效的:

编译成功:

let mut v2 = vec![1, 2, 3];
for i in &mut v2 {
    *i = *i + 1;
}
println!("{:?}", v2);

不编译:

let mut v1 = vec![1, 2, 3];
for ref mut i in v1 {
    *i = *i + 1;
}
println!("{:?}", v1);

似乎v已移动:

error[E0382]: use of moved value: `v1`
 --> src/main.rs:6:22
  |
3 |     for ref mut i in v1 {
  |                      -- value moved here
...
6 |     println!("{:?}", v1);
  |                      ^^ value used here after move
  |
  = note: move occurs because `v1` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait

1 个答案:

答案 0 :(得分:3)

您从书中引用的是正常作业的规则,例如let的作业。例如:

let x = &42;
let ref x = 42;

但是for循环中的名称绑定有些不同:

  • 要循环的值被转换为迭代器(<v1 as IntoIterator>::into_iter()),让我们调用该it的结果。
  • 然后反复调用it.next()
    • 如果它返回Some(_),则该值绑定到您的变量。就像您写了let Some(ref mut i) = it.next()let Some(mut i) = it.next()一样。 ref就是这里。
    • 如果返回None,则循环结束。

因此,在for循环情况下,ref&是不相等的。

在循环右侧使用&时,它不会直接更改变量的绑定;您只需更改要迭代的对象的类型。然后,一切都归结到IntoIterator的{​​{1}}实现和Vec<_>的实现。

  • 如果迭代&Vec<_>,则它将获得向量的所有权,并且迭代将自身返回值。因此Vec<T>使用向量,而for i in v1具有包含值i的类型。
  • 如果迭代T,它将借用向量,并且迭代返回指向包含的值&Vec<T>的指针,因此在&T中,for i in &v1的类型实际上是一个指针值。 i可以达到相同的效果。
  • 如果您迭代for i in v1.iter(),就像上一个一样,但它是可变的,因此迭代将返回&mut Vec<T>类型的值。

结论是,在&mut T循环中使用ref可能不太有用。