我正在寫一個小型的戰略遊戲,但我在實現一個循環鏈表時遇到了問題。無法在安全Rust中創建循環鏈表;不安全的版本崩潰
這款遊戲涉及到幾個人一個接一個地採取行動,並一輪一輪地遊戲結束。我認爲這可以通過使用一個循環鏈表完成,其中每個元素都是一個參考下一個玩家的玩家。該結構是這樣的:
#[derive(Debug, Clone)]
struct Player {
name: String,
killed: bool,
next: Option<Box<Player>>,
}
我也希望有一個指向當前活躍的球員,可以修改它的狀態,但我認爲鏽不允許我有相同的物體的兩個可變引用因爲每個玩家對下一個玩家都有一個可變的參考。
我想到的是,我可以使用一個簡單的可變參照Box
,它由其前一個玩家擁有並指向當前玩家。我寫了一個簡單的主要功能,發生問題:
fn main() {
let mut p3: Player = Player {
name: "C".to_string(),
killed: false,
next: None,
};
let mut p2: Player = Player {
name: "B".to_string(),
killed: false,
next: Some(unsafe { Box::from_raw(&mut p3) }),
};
let mut p1: Player = Player {
name: "A".to_string(),
killed: false,
next: Some(unsafe { Box::from_raw(&mut p2) }),
};
p3.next = Some(unsafe { Box::from_raw(&mut p1) });
println!("GAME STARTED!");
let mut current_player = p3.next.as_mut().unwrap();
let mut count = 0;
while count < 10 {
println!("Player to kill/save {}", current_player.name);
(*current_player).killed = !(*current_player).killed;
println!("Player {} is killed: {}",
(*current_player).name,
(*current_player).killed);
current_player = (*current_player).next.as_mut().unwrap();
count = count + 1
}
println!("End!");
}
錯誤也是關於可變性,但我不知道如何解決它。我想知道是否有更好的方法在Rust中實現這個想法,而不是使用循環鏈表和指向當前播放器的指針。也許我應該切換到另一個結構?
錯誤消息是相當長的,這裏是第幾行:
error: cannot borrow `current_player` (via `current_player.name`) as immutable because `current_player` is also borrowed as mutable (via `current_player.next`) [E0502]
println!("Player to kill/save {}", current_player.name);
^~~~~~~~~~~~~~~~~~~
note: mutable borrow occurs here (via `current_player.next`)
current_player = (*current_player).next.as_mut().unwrap();
^~~~~~~~~~~~~~~~~~~~~~
note: mutable borrow ends here
}
如果我改變as_mut()
方法as_ref()
它返回Box
的不可變的參考和註釋行
// (*current_player).killed = !(*current_player).killed;
該程序可以成功構建,但完成後會出現未知的運行時錯誤。不知道爲什麼會發生這種情況。
GAME STARTED!
Player to kill/save A
Player A is killed: false
Player to kill/save B
Player B is killed: false
......
Player to kill/save C
Player C is killed: false
Player to kill/save A
Player A is killed: false
End!
error: An unknown error occurred
我可能會忍不住上的'Vec'使用['迭代器:: cycle'(https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.cycle)球員而不是手動增加和包裝索引。 –
@ChrisEmerson這是一個好主意!不幸的是,你不能使用具有可變迭代器的'Iterator :: cycle':'std :: slice :: IterMut <...>:std :: clone :: Clone不滿足'。否則,我們可以同時獲取多個可變引用。我們可以更改矢量以包含'RefCell',並執行'borrow_mut'。 –
Shepmaster
@Shepmaster @Chris另一種允許'cycle'的方法是將'killed'改爲'Cell'。它似乎比'RefCell'更簡單。 –
krdln