error: cannot assign to immutable indexed content `i[..]`

error: cannot assign to immutable indexed content `i[..]`

在下面的 Rust 代码中,我试图更改数组的内容:

    let mut example_state = [[0;8]; 2];
    for mut i in example_state.iter() {
        let mut k = 0;
        for j in i.iter(){
            i[k] = 9u8;
            k +=1
        }
    }

但是我收到错误消息:

src/main.rs:18:13: 18:23 error: cannot assign to immutable indexed content `i[..]`
src/main.rs:18             i[k] = 9u8;

我对此感到困惑,因为我将 i 定义为 mut 并且 example_state 也是可变的。

我也不知道这是否是更改数组内容的最佳方式 - 我需要计数器 k 还是可以简单地以某种方式使用迭代器 j

更新: 所以我发现这段代码有效:

let mut example_state = [[n;8]; 2];
for i in example_state.iter_mut() {
    for j in i.iter_mut(){
        *j = 9u8;
    }
}

但我希望能解释一下它们之间的区别,iter_mut 在 Google 上不会吐太多。

我们来看看两个方法的签名,iter and iter_mut:

fn iter(&self) -> Iter<T>;
fn iter_mut(&mut self) -> IterMut<T>;

以及它们 return、Iter and IterMut 的结构,具体实现 Iterator:

// Iter
type Item = &'a T
// IterMut
type Item = &'a mut T 

这些是关联类型,但基本上在这种情况下,它们指定调用的return类型是什么Iterator::next。当你使用 iter 时,即使它是在一个可变变量上,你也在要求一个迭代器来 不可变引用 到类型 T (&T).这就是为什么你不能改变它们!

当您切换到 iter_mut 时,Iterator::next 的 return 类型是 &mut T,一个 可变引用 输入 T。您可以设置这些值!

顺便说一句,你的问题使用了 arrays,而不是 slices,但是没有数组的文档链接(我可以快速找到),并且切片足够接近数组,所以我用它们来解释。

这里有两个正交的概念:

  • 引用本身是否可变。这就是imut i的区别。

  • 它指向的数据是否可变。这就是.iter()/&T.iter_mut()/&mut T的区别。

如果你用过C,这个区别应该不会陌生。您的初始代码创建 可变引用 不可变数据 ,或 C 中的 const char *。因此,虽然您可以分配给引用本身(i = ...),你不能修改它指向的数据(*i = ...)。这就是编译器阻止你的原因。

另一方面,您的固定代码创建了可变数据的不可变引用。那是 C 中的 char * const。这不允许您分配给引用本身,但它确实允许您修改底层数组,因此它按预期编译。


那么为什么 Rust 有单独的 .iter().iter_mut()?因为在 Rust 中,虽然您可以根据需要对一个结构使用多个 &T,但您只能通过一个 &mut T 来修改它。换句话说,可变引用是唯一的,永远不会 alias.

同时拥有 .iter().iter_mut() 给您一个选择。一方面,您可以同时在范围内拥有任意数量的不可变迭代器,它们都指向同一个数组。这是一个同时向前和向后迭代的愚蠢示例:

for i, j in array.iter().zip(array.iter().rev()) {
    println!("{} {}", i, j);
}

但是如果你想要一个可变的迭代器,你必须保证引用永远不会别名。所以这行不通:

// Won't compile
for i, j in array.iter_mut().zip(array.iter_mut().rev()) {
    println!("{} {}", i, j);
}

因为编译器无法保证 ij 不会指向内存中的同一位置。