在结构体中遍历Vec——无法移动已借用的内容

12

我正在为一个包含Vec的结构编写一个函数,尝试遍历该Vec

我正在编写一个函数来处理一个包含Vec的结构体,在函数中我试图对Vec进行迭代。

struct Object {
    pub v: Vec<f32>,
}

impl Object {
    pub fn sum(&self) -> f32 {
        let mut sum = 0.0;
        for e in self.v {
            sum += e;
        }
        sum
    }
}

然而我遇到了以下错误:

error[E0507]: cannot move out of borrowed content
 --> src/lib.rs:8:18
  |
8 |         for e in self.v {
  |                  ^^^^ cannot move out of borrowed content

我的理解是由于self被借用且for循环迭代尝试将v的元素移动到e中,因此出现了这个错误。

从错误代码中,我读到一个潜在的解决方案是取得所有权,但我不太确定如何做到这一点。

我并没有试图修改向量或其元素。 我只想使用这些元素来运行一些计算。

1个回答

22

这行代码:for e in self.v 实际上是 for e in (*self).v 的缩写; 你试图通过移动方式来迭代向量,并调用它的IntoIterator特性。这会完全摧毁向量,永久性地移动所有数字,这不仅不是你想要的,也在这种情况下是不允许的,因为你只能读取它。

实际上,你需要通过引用迭代它。有两种方法可以做到这一点:

for e in &self.v {
    // ...
}
这基本上等同于&((*self).v),因为.操作符会进行自动解引用,你需要告诉编译器你只想借用这个向量。

或者
for e in self.v.iter() {
    // ...
}

这看起来很有趣,因为 iter 接受一个 &self。为什么呢?好吧,如果您在值上调用需要引用的函数,编译器也会自动引用。这实际上是 (&((*self).v)).iter(),但写起来很麻烦,所以编译器提供了帮助。

那么为什么 for 循环不自动引用呢?好吧,for x in self.v 是有效的语句,那可能就是您想要编写的内容。编译器更重要的是告诉您想要的是否不可能,而不是假定您想要其他内容。使用自动引用和解引用,不存在这种歧义。

前一种解决方案更优,但如果您想使用迭代器适配器,则必须使用后一种方案。

说到这一点,您已经拥有了 sum:只需编写 self.v.iter().sum()


太棒了,它完美地运行了。非常感谢。这是否意味着每当调用 self.struct_member 时,Rust 编译器将其视为 (*self).struct_member 并移出结构体?还是只适用于 for x in self.v 结构? - illeyezur
@illeyezur 这总是发生的情况(除了Copy类型,但这是因为Copy类型不会在一般情况下移动)。 - Linear

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接