Hi, classic question today as I've been struggling with a situation where I just cannot figure out how I'm supposed to do what I want with the borrow mechanism.
So here's the problem. I have a region which contains a bunch of teams and I am parsing a JSON dataset to find the result of a bunch of matches. So first, I need to find the teams, and once I have found them I need to simulate the match to update the ratings of both. This means the teams have to be mutable.
Currently in the code, it compiles because everything is immutable and so I'm not updating any rating:
let region = get_region(®ions, series.region.clone())?;
let blue_team = region.get_team(blue_ref.name.clone(), &blue_players)?;
let orange_team = region.get_team(orange_ref.name.clone(), &orange_players)?;
simulate_match(blue_team, orange_team);
Now the problem is, if I want to update the rating of the 2 teams, I need get_team() to return a mutable team, and if I do this I need region to be mutable as well. But then... I have 2 mutable references pointing on the same vector.
I've also tried to change to make a get_teams() to return both teams in a vec directly, but then I have the exact same problem, just inside the get_teams() function instead. I just cannot find a way to get 2 teams that belong to the same vector as mutables so that they can both be updated.
The best solution depends on the context. But there are several alternatives:
if you are sure you have distinct indices, then you can use split_at_mut() to get mutable references to different elements to the same slice, like this.
or you can return immutable references, cache the necessary modifications (e.g., scores), and then after the computation is done, release the immutable borrows, and mutably borrow the teams separately, performing the updates one-by-one.
Ah okay I wasn't aware about split_at_mut()! I assume I need to first find the position of both elements to know if I should invert or not the return, but this should work! Thanks, I'll try it out
Okay I think I see how that could work ; good point about implementing PartialEq<(&str, &[Player])> that would really clear up my code, thanks for the suggestion as well!
The dumb, general option, is to return an index instead of a ref for lookups, but you have to be careful if the collection itself can be reordered or otherwise invalidating those indices (if it can be, switching from a vec to a hashmap can be a simple solution, but there's specialized crates for better performance)