2016-02-26 47 views
4

我已經開始學習Rust,並試圖實現一個簡單的一維元胞自動機。我想將自動機狀態(Board)表示爲包含大小和兩個不同向量(具有相同大小)的結構。我試過了:如何交換結構的兩個字段

struct Board { 
    n: usize, 
    cur: Vec<u32>, 
    next: Vec<u32>, 
} 

impl Board { 
    fn new(size: usize) -> Board { 
     Board { 
      n: size, 
      cur: vec![0;size], 
      next: vec![0;size], 
     } 
    } 
} 

到目前爲止好。我也能夠突變這兩個載體。但我希望能夠交換兩個向量(或者更確切地說,它們的引用),如:

fn swap(&mut self) -> &Board { 
    let tmp = self.cur; 
    self.cur = self.next; 
    self.next = tmp; 
    self 
} 

它失敗,與cannot move out of borrowed content [E0507],我想我能理解。我也試過mem::swap,我在類似的題目問題中發現沒有成功。

我該如何讓這個例子工作? (由於我是Rust的初學者,請不要猶豫,建議一個不同的數據表示形式)。

回答

4

正如你注意到,mem::swap是要走的路:

fn swap(&mut self) -> &Board { 
    std::mem::swap(&mut self.cur, &mut self.next); 
    self 
} 

這工作。請注意,在使用.時,您正在解除引用self。所以雖然self的類型爲&mut Board,self.cur的類型爲Vec<u32>。因此,編譯器抱怨「移出借用內容」,我們需要額外的&mut

4

什麼問題?

您是衝孔在您的數據:

fn swap(&mut self) -> &Board { 
    let tmp = self.cur;   // 1 
    self.cur = self.next;  // 2 
    self.next = tmp;   // 3 
    self 
} 

如果我們用線分析線:

  1. self.cur現在初始化
  2. self.next現在初始化
  3. 一切都是潔淨的獲得

如果由於某種原因計算中斷線路(3)具有改變收緊的情況下,self現在中毒之前,可能會導致各種討厭的事情發生。值得注意的是,它的析構函數可能會試圖釋放內存兩次。

從理論上講,你可以有臨時孔編譯器檢查和證明,毫無疑問,認爲:

  • 沒有函數訪問self而孔衝壓
  • 由範圍的結束,無論是它是正常達到或通過展開,孔再次填滿

事實上在某些時候它被認爲是......但事實是它很複雜,並且有可用的解決方法。

那麼,

答案在於std::mem,它揭示了以安全方式執行這樣的低級操作的功能。雖然這些功能本身是在底層使用unsafe實現的,但他們依靠對語言和運行時的理解來公開安全的接口。

兩個特定功能,將您感興趣的是:

  • replace:由src: T取代的dest: &mut T的內容和返回什麼原載於背後dest
  • swap:交流它的參數內容

使用這兩個簡單和安全的基元,可以避免在數據中出現空洞。