I agree with @erelde that the best solution is probably to change update from
fn update(mut self) -> Self {
to
fn update(&mut self) {
Some explanation as to why and what the alternative would be:
The two signatures are actually very similar, the mutable reference approach has e.g. the advantage that no value has to be moved around (lots of moving can have some overhead), the main difference however is the behavior on a panic. One might expect that something like
let team1 = team_map.entry("Team1".to_string()).or_insert(Team::new());
*team1 = team1.update();
ought to compile with the (mut self) -> Self version of update, the problem however is: what happens if update panics? In this case, there would be no Team value left inside of the HashMap, which is problematic i.e. not okay. There are crates like replace_with that allow you to move out and then move back into a mutable reference by handling the panic case with a default value (or e.g. by aborting the program if you use replace_with_or_abort). With that, you can do something like this:
use std::collections::HashMap;
use replace_with::replace_with;
struct Team {}
impl Team {
fn new() -> Self {
Team {}
}
fn update(mut self) -> Self {
self
}
}
fn main() {
let mut team_map: HashMap<String, Team> = HashMap::new();
let team1 = team_map.entry("Team1".to_string()).or_insert_with(Team::new);
replace_with(team1, Team::new, |team| team.update());
// ^^^^^^^^^ only called if `update` panics
}
Anyways, all this is a lot easier if you have an fn update(&mut self) instead, as with this signature, the update function guarantees that there’s still some (potentially “garbage”-valued) Team in place in case of a panic.
use std::collections::HashMap;
struct Team {}
impl Team {
fn new() -> Self {
Team {}
}
fn update(&mut self) {
}
}
fn main() {
let mut team_map: HashMap<String, Team> = HashMap::new();
let team1 = team_map.entry("Team1".to_string()).or_insert(Team::new());
team1.update();
}
By the way, a useful thing to keep in mind is the function mem::replace (and its friends mem::take and mem::swap). If you’re fine with always taking the overhead of constructing and moving a dummy value into the mutable reference, you can use mem::replace as an alternative approach similar to replace_with: Rust Playground