Well, first of all,
fn work(&mut self) { ... }
is an abbreviation for
fn work(self: &mut Self) { ... }
which in turn stands for
fn work(self: &mut MyStruct) { ... }
in the context of an impl MyStruct.
So self is a mutable reference to MyStruct, i.e. a &mut MyStruct.
This means, that in order to pass a MyStruct and not a &mut MyStruct to the modify function, since modify expects a MyStruct, you cannot pass self instead, but e.g. need to dereference the reference self. Something like
*self = modify(*self);
This doesn’t quite compile yet, though.
The problem now is that you cannot easily take the value out of a &mut MyStruct reference. At least for a type that isn’t Copy the Copy trait allows you to, among other things, do something like for example dereferencing a &mut i32 by copying the number behind the reference.
In order to do *self = modify(*self), using Rust’s move semantics, it would need to be possible to:
- take/move the value out of the
self: &mut MyStruct reference
- then call
modify
- finally, move the result back into the place that
self points to
however, if modify were to exit with a panic, then work would leave the reference self pointing to no valid value, which doesn’t work.
The usual workaround for something like this is to use mem::replace or something similar, and put in an intermediate dummy value. E.g.
fn work(&mut self) {
let this = std::mem::replace(self, MyStruct { counter: 0 });
let this = modify(this);
*self = modify(this);
}
Another alternative is to copy the entire struct, e.g. like this
fn work(&mut self) {
let new_self = modify(MyStruct {
counter: self.counter,
});
*self = modify(new_self);
}
or by adding the Clone and/or Copy trait:
#[derive(Clone)]
struct MyStruct {
pub counter: i32,
}
// ...
fn work(&mut self) {
let new_self = modify(self.clone());
*self = modify(new_self);
}
or
#[derive(Clone, Copy)]
struct MyStruct {
pub counter: i32,
}
// ...
fn work(&mut self) {
*self = modify(*self);
*self = modify(*self);
}
The arguably more sane thing to do here though is to change modify into taking &mut MyStruct itself, too, i.e.
struct MyStruct {
pub counter: i32,
}
fn modify (my_struct: &mut MyStruct) {
my_struct.counter += 1;
}
impl MyStruct {
fn work(&mut self) {
modify(self);
modify(self);
}
}
fn main() {
let mut my_struct = MyStruct {counter: 0};
my_struct.work();
}