2017-08-26 40 views
1

我有一個由結構Manager擁有的對象的集合。這些對象具有可選屬性,如printabledynamic。我想重複循環所有可打印的對象來打印它們並遍歷所有動態對象來更新它們。我比較幼稚的實現是這樣的:如何重複循環由項目屬性確定的集合的子集?

struct Object { 
    state: i32, 
    printable: Option<i32>, 
    dynamic: Option<i32> 
} 

struct Manager { 
    objects: Vec<Object>, 
} 

impl Manager { 
    fn print_objects(&self) { 
     for o in &self.objects { 
      if let Some(i) = o.printable { 
       print!("{}: {}, ", i, o.state); 
      } 
     } 
     println!(); 
    } 

    fn update_objects(&mut self) { 
     for o in &mut self.objects { 
      if let Some(i) = o.dynamic { 
       o.state += i; 
      } 
     } 
    } 
} 

fn main() { 
    let mut mgr = Manager{objects: Vec::new()}; 

    mgr.objects.push(Object{state: 0, printable: Some(10), dynamic: None}); 
    mgr.objects.push(Object{state: 0, printable: None, dynamic: Some(1)}); 
    mgr.objects.push(Object{state: 0, printable: Some(20), dynamic: Some(2)}); 

    for _ in 0..3 { 
     mgr.update_objects(); 
     mgr.print_objects(); 
    } 
} 

該解決方案,它需要遍歷所有對象和檢查每對相應的標誌的缺點。假設只有一小部分對象是動態的,我寧願避免循環遍歷所有對象。在C++中,我只需創建一個指向動態對象的指針列表並循環。在嘗試此:

struct Manager<'a> { 
    objects: Vec<Object>,  // objects owned by Manager 
    dynamic: Vec<&'a Object> // references to dynamic objects 
} 

impl<'a> Manager<'a> { /* ... */ } 

fn main() { 
    let mut mgr = Manager{objects: Vec::new(), dynamic: Vec::new()}; 

    mgr.objects.push(Object{state: 0, printable: Some(10), dynamic: None}); 
    mgr.objects.push(Object{state: 0, printable: None, dynamic: Some(1)}); 
    mgr.objects.push(Object{state: 0, printable: Some(20), dynamic: Some(2)}); 

    mgr.dynamic.push(&mgr.objects[1]); 
    mgr.dynamic.push(&mgr.objects[2]); 

    for _ in 0..3 { 
     mgr.update_objects(); // can't mutably borrow because of reference held by mgr.dynamic 
     mgr.print_objects(); 
    } 
} 

這似乎是我不能保持對元素的引用在Manager.objects,並在同一時間借用它性情不定地一個非常基本的問題。因此,我開始懷疑我的整個方法。有沒有一種慣用的方式來實施Rust的這種模式?

我相信保持對象的引用可以防止我對它們進行變異,但我很樂意學習一種解決方法。未來的目標是在更新期間更改printabledynamic,但我想在處理該步驟之前弄清楚基本內容。

+2

你可以在第一個向量中創建一個索引向量,但是我不知道這是多麼地道 - 這看起來有點像作弊以避開安全檢查。這會導致問題,例如如果源矢量中項目的順序改變。 – interjay

+0

@interjay它不是*作弊*,它只是另一個間接級別,但可以在運行時檢查安全性(通過邊界檢查)。在編譯時檢查引用。如果允許,可能會因爲您提到的原因而失效。 – Shepmaster

+0

@Shepmaster這是安全的,它不會導致無效的內存訪問錯誤。但是如果你之前刪除了vector中的一個元素,那麼它會訪問錯誤的元素,即使它在Rust術語中不是不安全的,我也會認爲它是不安全的(程度較低)。 – interjay

回答

2
struct Manager<'a> { 
    objects: Vec<Object>,  // objects owned by Manager 
    dynamic: Vec<&'a Object> // references to dynamic objects 
} 

這不起作用,並已在Why can't I store a value and a reference to that value in the same struct?中進行了充分討論。

一種解決方案是擁有多個所有者的單個值,稱爲共享所有權。一種實現是Rc

您還希望具有與程序範圍無關的可變性,而是與運行時特性相關,該運行時特性可使用內部可變性啓用。的一種實現方式是RefCell

use std::rc::Rc; 
use std::cell::RefCell; 

#[derive(Debug)] 
struct Object { 
    state: i32, 
    printable: Option<i32>, 
    dynamic: Option<i32>, 
} 

#[derive(Debug, Default)] 
struct Manager { 
    objects: Vec<Rc<RefCell<Object>>>, 
    printable: Vec<Rc<RefCell<Object>>>, 
    dynamic: Vec<Rc<RefCell<Object>>>, 
} 

impl Manager { 
    fn add(&mut self, state: i32, printable: Option<i32>, dynamic: Option<i32>) { 
     let obj = Object { state, printable, dynamic }; 
     let obj = Rc::new(RefCell::new(obj)); 

     self.objects.push(obj.clone()); 

     if printable.is_some() { 
      self.printable.push(obj.clone()) 
     } 

     if dynamic.is_some() { 
      self.dynamic.push(obj.clone()) 
     } 
    } 

    fn print_objects(&self) { 
     for o in &self.printable { 
      let o = o.borrow(); 
      if let Some(i) = o.printable { 
       print!("{}: {}, ", i, o.state); 
      } 
     } 
     println!(); 
    } 

    fn update_objects(&mut self) { 
     for o in &self.dynamic { 
      let mut o = o.borrow_mut(); 
      if let Some(i) = o.dynamic { 
       o.state += i; 
      } 
     } 
    } 
} 

fn main() { 
    let mut mgr = Manager::default(); 

    mgr.add(0, Some(10), None); 
    mgr.add(0, None, Some(1)); 
    mgr.add(0, Some(20), Some(2)); 

    for _ in 0..3 { 
     mgr.update_objects(); 
     mgr.print_objects(); 
    } 
} 

你還有從一個組轉移的項目之間的所有固有的問題。

+0

回想起來似乎很明顯。令人驚訝的是,學習鐵鏽讓我覺得所有人都無能爲力......無論如何,非常感謝! – kazemakase

相關問題