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,但是没有数组的文档链接(我可以快速找到),并且切片足够接近数组,所以我用它们来解释。
这里有两个正交的概念:
引用本身是否可变。这就是i
和mut 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);
}
因为编译器无法保证 i
和 j
不会指向内存中的同一位置。
在下面的 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,但是没有数组的文档链接(我可以快速找到),并且切片足够接近数组,所以我用它们来解释。
这里有两个正交的概念:
引用本身是否可变。这就是
i
和mut 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);
}
因为编译器无法保证 i
和 j
不会指向内存中的同一位置。