2017-04-21 62 views
1

我有一個vec一些結構類型,我想改變矢量中的第一個元素的一些領域。我怎樣才能做到這一點?如何更改Rust中向量中元素的字段?

例子:

struct SomeType { 
    some_value: i32, 
} 

fn main() { 
    let mut vec = Vec::new(); 
    let mut t = SomeType { some_value: 45 }; 
    vec.push(t); 

    println!("Old value: {}", vec.first().unwrap().some_value); 
    vec.first().unwrap().some_value += 1; 
    println!("New value: {}", vec.first().unwrap().some_value); 
} 

這無法編譯:

error: cannot assign to immutable field 
    --> vec.rs:15:2 
    | 
15 | vec.first().unwrap().some_value += 1; 
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot mutably borrow immutable field 

我不能讓我的周圍魯斯特突變性的東西還沒有頭;這裏的正確方法是什麼?

回答

4

要突變矢量的第一個元素,通常會獲得對該元素的引用。換句話說,將參考文獻分成這個載體。作爲一個正常的結構,矢量需要有一個方法來爲你提供參考。

事情是,對矢量的引用意味着你可以對矢量的內部做些事情,閱讀它們或以某種方式修改它們。 Rust不知道細節,它只是知道,當你拿着那個參考時,你可以做些東西。

只有那些有限的信息,Rust的借用檢查器試圖阻止你在腳下射擊自己。它說:如果你要閱讀矢量,那麼很好,你可以以任何你想要的方式讀取它,甚至可以讓其他功能讀取它,或者兩個函數,或者五個函數。但是當你閱讀時你不能修改這個矢量,這是不安全的,它會導致錯誤。所以,你可以在你想要的地方有儘可能多的只讀引用,但只有當你沒有持有任何可寫入的引用時纔可以。如果您持有可寫參考,則一次只能有一個此類參考。

因此,這種參考很重要。這就是爲什麼矢量有兩種方法給你第一個元素:firstfirst_mut

所以這裏

let mut vec = Vec::new(); 

您的載體已經是可變的。而來自其他語言的人可能會從直覺上得出結論,如果這個向量是可變的,那麼它總是可變的。有點像C++中的const值或D中的immutable。它可以是可變的,也可以不是。

但是在Rust中你可能想要不可變的引用進入可變結構。例如,你可能想要一個線程在矢量的一個元素上工作,另一個線程在另一個元素上工作,如果你想讓藉助檢查器的安全帶保持打開,那麼擁有多個引用的最簡單的方法就是讓它們不可變。這就是爲什麼像first這樣的方法返回不可變引用並獲得需要通過使用不同方法顯式選擇的可變引用。

P.S.那有什麼幫助?

+0

感謝您的詳細解釋!確實來自C++,我試着處理類似於「const」的東西,現在我對它有了更好的理解。 –

2

這裏的同樣的工作代碼示例:

vec[0].some_value += 1; 

vec.first_mut().unwrap().some_value += 1; 

與代碼顯示在的問題是,first()到第一元件,而可變引用返回一個(不可變)參考是必需的問題。

索引([0])的工作原理是這樣的:

  1. vec derefs切片
  2. 索引片上呼籲index_mut方法從IndexMut特質
  3. index_mut方法返回可變引用(&mut someType
+0

感謝這些例子,這比預期的更容易。我希望你不要介意我接受了ArtemGr的回答,因爲他提供了非常詳細的解釋。 –

0

我認爲你在尋找&mut whe ñ參考。

#[derive(Debug)] 
struct Character{ 
    name: String, 
} 

fn main() { 
    let mut hobbits = vec![ 
     Character{name:String::from("Sam")}, 
     Character{name:String::from("Merry")}, 
     Character{name:String::from("Pepper")}, 
    ]; 

    { 
     let third = &mut hobbits[2]; 
     third.name = String::from("Pippin"); 
    } 

    println!("{:?}", hobbits); 
} 

注意{}圍繞可變元素引用。它需要限制可變參考範圍。不能同時具有可變和不可變引用:println!將失敗,而third仍在範圍內。