简体   繁体   中英

How can I do a mutable borrow after an immutable borrow?

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

I understand this

  1. 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

  2. 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

Question

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).

here is example code

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM