The code
fn play(&self, game: &mut crate::game::Game) {
let player_in_turn: &Player = game.get_player_in_turn();
match player_in_turn.player_kind {
PlayerKind::AI => {
player_in_turn.do_random_move(&mut game);
}
_ => {
panic!("not implemented yet");
}
}
game.status = Status::ExitGame;
}
Where get_player_in_turn
is
pub fn get_player_in_turn(&self) -> &Player {
match self.status {
Status::InGame(ig_status) => match ig_status {
InGameStatus::PlayFirst => {
if self.player_a.play_order == PlayOrder::First {
&self.player_a
} else {
&self.player_b
}
}
InGameStatus::PlaySecond => {
if self.player_a.play_order == PlayOrder::Second {
&self.player_a
} else {
&self.player_b
}
}
},
_ => {
panic!("get_player_in_turn called when not in a in-game status");
}
}
}
The compiler is telling me
error[E0502]: cannot borrow `game` as mutable because it is also borrowed as immutable
--> src\game\status\in_game_status.rs:28:47
|
25 | let player_in_turn: &Player = game.get_player_in_turn();
| ------------------------- immutable borrow occurs here
...
28 | player_in_turn.do_random_move(&mut game);
| -------------- ^^^^^^^^^ mutable borrow occurs here
| |
| immutable borrow later used by call
Usually I am able to understand the what and the why of compilers erros
let player_in_turn: &Player = game.get_player_in_turn();
: I keep from game
a ref to the current player; so I get an immutable ref of kind &Player
Here the game
variable is immutably borrowed because of fn signature get_player_in_turn(&self)
. That's right, I do not want allow modifications to game in the get_player_in_turn, but also I need a ref because I need the player in turn, not a copy, or what else
player_in_turn.do_random_move(&mut game);
: The instance of Player now alters the game itself doing its move
And here game
should be passed as mutable because it's the goal of do_random_move
I can understand the why of this but not how can I workaround
As you said, you know why this happens. Optimal workaround is to rewrite your code to use less borrowing. So you definitely can't do that if you want to modify some previously borrowed data. But if your do_random_move()
function does not change internals of Player
s, then you can use this design pattern .
The core idea is to split borrowing into parts. Right now you are borrowing full Game
structure when calling get_player_in_turn
, but you only need 3 fields there: status, player_a, player_b
. You can create a new function that takes them as arguments and this will split your borrowing and will allow you to borrow other fields of Game
later (probably for do_random_move
implementation).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.