Not quite correct. First of all, +=
may be implemented differently than what +
does. Moreover, if you write a = a + b
and if the type of a
isn't Copy
, then you temporarily move out of a
which means in case of a panic during execution of std::ops::Add::add
, the value a
would be set to no value. This leads to the compiler refusing this operation in some contexts:
#[derive(Debug)]
struct Person {
name: String,
height: u32,
}
fn foo(person: &mut Person) {
person.height = person.height + 5; // this works
//person.name = person.name + " Doe"; // but this doesn't compile
person.name += " Doe"; // even though it does the same as this
}
fn main() {
let mut p = Person {
name: "John".to_string(),
height: 100,
};
foo(&mut p);
println!("{p:?}");
}
In the example above, person.height = person.height + 5;
works fine. But person.name = person.name + " Doe";
does not work because if that operation would panic, then person.name
would not be valid anymore.
Sometimes this isn't a problem, like when you do the operation direction in main
, because a panic would cause p
to be dropped.
#[derive(Debug)]
struct Person {
name: String,
height: u32,
}
// Try to uncomment this:
//impl Drop for Person {
// fn drop(&mut self) {
// }
//}
fn main() {
let mut p = Person {
name: "John".to_string(),
height: 100,
};
p.height = p.height + 5;
p.name = p.name + " Doe"; // in this context, the line works, unless `Person` implements `Drop`
p.name += " Doe";
println!("{p:?}");
}
However, that only works if Person
doesn't have a drop handler, because if it had, then p.name
might be invalid when the drop handler runs.
P.S.: Regarding consuming a value and returning a new one versus working on &mut
references, I found this post by @steffahn very enlightening (which is why I came up with the above examples in regard to panic behavior and partial moves).