我有一個由結構Manager
擁有的對象的集合。這些對象具有可選屬性,如printable
或dynamic
。我想重複循環所有可打印的對象來打印它們並遍歷所有動態對象來更新它們。我比較幼稚的實現是這樣的:如何重複循環由項目屬性確定的集合的子集?
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的這種模式?
我相信保持對象的引用可以防止我對它們進行變異,但我很樂意學習一種解決方法。未來的目標是在更新期間更改printable
或dynamic
,但我想在處理該步驟之前弄清楚基本內容。
你可以在第一個向量中創建一個索引向量,但是我不知道這是多麼地道 - 這看起來有點像作弊以避開安全檢查。這會導致問題,例如如果源矢量中項目的順序改變。 – interjay
@interjay它不是*作弊*,它只是另一個間接級別,但可以在運行時檢查安全性(通過邊界檢查)。在編譯時檢查引用。如果允許,可能會因爲您提到的原因而失效。 – Shepmaster
@Shepmaster這是安全的,它不會導致無效的內存訪問錯誤。但是如果你之前刪除了vector中的一個元素,那麼它會訪問錯誤的元素,即使它在Rust術語中不是不安全的,我也會認爲它是不安全的(程度較低)。 – interjay