2015-01-26 48 views
10

在以下的锈代码我试图更改数组的内容:错误:不能分配到不可变索引内容`我[..]`

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定义为mutexample_state也是可变的。

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

UPDATE: 所以我发现这个代码块的工作:

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

,但我会很感激的区别是它们之间有什么一些解释,iter_mut不投在谷歌了。

+0

是不是所有的代码只是'let example_state = [[9u8; 8]; 2]'? – 2015-01-26 22:53:47

+1

这是一个更复杂的简单例子 - 我试图理解为什么这个*不起作用。 – 2015-01-26 22:59:14

+0

够公平的。无论如何,这是个好问题。 – 2015-01-26 23:00:33

回答

5

让我们看看这两种方法,iteriter_mut的签名:

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

而且它们返回的结构,IterIterMut,具体的Iterator实现:

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

这些都是关联类型,但基本上在这种情况下,它们指定了返回类型调用Iterator::next。当您使用iter时,即使它是在一个可变变量上,您仍然要求迭代器将不可变引用转换为类型T&T)。这就是为什么你不能改变他们!

当你切换到iter_mutIterator::next返回类型是&mut T,一个可变引用一个类型T。您可以设置这些值!

顺便说一句,你的问题用阵列,不,但目前还没有对数组的文档链接(我能很快找到),和切片足够接近阵列,所以我用他们的这一说明。

+0

你如何检查方法签名? – 2015-01-27 21:05:38

+0

@MikeVella我只是指[文档](http://doc.rust-lang.org/std/),它有一个全面的搜索功能。 Rustdoc正在积极开展工作,所以有时候我必须去[源代码潜水](https://github.com/rust-lang/rust)。那么这只是寻找'fn my_name'的问题! – Shepmaster 2015-01-27 22:01:02

4

有两个正交的概念怎么回事:

  • 无论引用本身是可变的。这是imut i之间的差异。

  • 数据是否指向是可变的。这是.iter()/&T.iter_mut()/&mut T之间的差异。

如果您使用C,这种区别应该很熟悉。您最初的代码创建可变引用不可变的数据,或const char *在C.因此,尽管你可以分配给基准本身(i = ...),你不能修改它指向(*i = ...)的数据。这就是编译器阻止你的原因。

在另一方面,您的固定代码创建不可改变引用可变数据。这是C中的char * const。这不会让您分配给引用本身,但它可以让您修改底层数组,以便按预期进行编译。


那么,为什么锈病有一个单独的.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没有指向同一个内存位置。

相关问题