rustlings
rustlings copied to clipboard
hashmaps3 double borrow
Hello, I am new with Rust!
Trying to solve the exercise like this:
let team1 = Team {goals_scored: 0, goals_conceded: 0};
let entry1 = scores.entry(team_1_name).or_insert(team1);
let team2 = Team {goals_scored: 0, goals_conceded: 0};
let entry2 = scores.entry(team_2_name).or_insert(team2);
entry1.goals_scored += team_1_score;
entry1.goals_conceded += team_2_score;
entry2.goals_scored += team_2_score;
entry2.goals_conceded += team_1_score;
produces the following error:
Compiling of exercises/hashmaps/hashmaps3.rs failed! Please try again. Here's the output:
error[E0499]: cannot borrow `scores` as mutable more than once at a time
--> exercises/hashmaps/hashmaps3.rs:46:22
|
43 | let entry1 = scores.entry(team_1_name).or_insert(team1);
| ------------------------- first mutable borrow occurs here
...
46 | let entry2 = scores.entry(team_2_name).or_insert(team2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
47 |
48 | entry1.goals_scored += team_1_score;
| ----------------------------------- first borrow later used here
error: aborting due to previous error
For more information about this error, try `rustc --explain E0499`.
which makes sense because I am borrowing 2 mutable references to scores entries. But when I permute the code like this
let team1 = Team {goals_scored: 0, goals_conceded: 0};
let entry1 = scores.entry(team_1_name).or_insert(team1);
entry1.goals_scored += team_1_score;
entry1.goals_conceded += team_2_score;
let team2 = Team {goals_scored: 0, goals_conceded: 0};
let entry2 = scores.entry(team_2_name).or_insert(team2);
entry2.goals_scored += team_2_score;
entry2.goals_conceded += team_1_score;
it compiles and pass the test.
Why this change make it work? I guess the compiler should not be able to distinguish that the entries are different by just looking at the code in both scenarios.
The compiler is smart enough to distinguish that entry1 is no longer being accessed and therefore allows entry2. After the line
let entry2 = scores.entry(team_2_name).or_insert(team2);
You are no longer allowed to access entry1.
For more info see https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html
Note that a reference’s scope starts from where it is introduced and continues through the last time that reference is used. For instance, this code will compile because the last usage of the immutable references, the println!, occurs before the mutable reference is introduced...
The scopes of the immutable references r1 and r2 end after the println! where they are last used, which is before the mutable reference r3 is created. These scopes don’t overlap, so this code is allowed: the compiler can tell that the reference is no longer being used at a point before the end of the scope.