在 Rust 中对迭代器进行嵌套循环

7
在C语言中,我可以使用索引以嵌套的方式可变地迭代数组。在Rust中,我可以使用索引实现类似的操作,但是如果我想使用迭代器而不是索引怎么办?
例如下面的代码段编译成功,因为两个借用都是不可变的:
let xs = [0, 1, 2];
for x in &xs {
    for y in &xs {
        println!("x={} y={}", *x, *y);
    }
}

但是如果我想使用可变迭代器呢?

let mut xs = [0, 1, 2];
for x in &mut xs {
    *x += 1;
    for y in &mut xs {
        *y += 1;
        println!("x={} y={}", *x, *y);
    }
}

这将导致:
error[E0499]: cannot borrow `xs` as mutable more than once at a time

我理解需要限制数据的写入访问,但我也想知道有经验的Rust用户如何仅使用迭代器实现这一点 - 假设出于教育目的,索引不可用。

1
正如在此线程中指出的那样,可以使用while let来实现这个目的。 - Misty
3
这篇文章深入探讨了这个问题。 - cdhowie
2
无法使用迭代器来完成此操作,因为在某个时刻,xy 指向 xs 中的同一项并用于更改此项。除了使用索引之外,唯一的解决方法是将 xs 更改为 Cell 向量,以限制可变访问的范围。 - Jmb
1个回答

4
我理解需要控制对数据的写入访问,但我也想知道有经验的 Rust 用户如何仅使用迭代器来实现。
他们不会这样做,因为这并不可行,至少不能像原来那样:虽然将其展开为 while let 是一种常见方法,但它适用于嵌套循环,其中您想要在外部和内部循环中推进相同的迭代器,这避免了跨越整个循环的独占借用的需要。
但是,在这里,您不希望在不同的位置推进相同的迭代器,而是希望对同一集合进行两个不同的可变迭代器。这意味着您对同一集合具有两个不同的可变引用(这是不允许的),并且最终您将拥有对集合项的两个可变引用(这也是不允许的)。
最好的办法是使用内部可变性来解决此问题,例如:
let xs = [Cell::new(0), Cell::new(1), Cell::new(2)];
for x in &xs {
    x.set(x.get() + 1);
    for y in &xs {
        y.set(y.get() + 1);
        println!("x={} y={}", x.get(), y.get());
    }
}

但我认为这不是通常的选择(回退到索引会更好,因为它不需要改变数据本身)。


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