2015-01-26 51 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沒有指向同一個內存位置。

相關問題