Pass self reference to contained object's function
Solution 1:
One way to follow Shepmaster's solution
disassociate
player
fromself
before calling the method.
Is to put the player
in an Option
:
impl App {
pub fn sender(&mut self) {
let mut player = self.player.take();
player.receive(&mut self);
self.player = Some(player);
}
}
One last resource is to use RefCell
.
Solution 2:
because
App
has move semantics so the value was moved into thesender
function when it was called.
It's true that it was moved into sender
, but that's not what this message is about. Because Player::receive
takes self
by value, you actually had to decompose app
and move player
out of it to be able to call receive
. At that point in time, app
is now half-formed; it has no valid value for player
! If receive
tried to access app.player
, it would be using invalid memory.
"cannot move out of borrowed content" [...] because we've borrowed the reference to
self
when we went into thesender
function.
Right, which ties into above. Because we are borrowing an App
, we cannot move player
out of it, leaving the App
in a invalid state.
I should be able to borrow a reference and perform operations on it, no?
And you can, so long as the thing you are taking a reference to is completely formed at that point. There were also two hints in the above exposition:
-
If
receive
tried to accessapp.player
If you don't access
app.player
inreceive
, restructure your code to pass the other components ofApp
instead of the entire container. Maybe you have someGameState
that is really what you want to pass. -
leaving the
App
in a invalid stateYou can use something like
mem::replace
to put in a differentPlayer
intoapp
. Then it's still completely (but differently) formed and can have a reference to it taken again.
Of course, the more practical solution is to change to accept references (&self
).
But what if I want
app
to be mutable inreceive
?
Yup! You'd get "cannot borrow *self
as mutable more than once at a time". The solutions are actually basically the same, however! Decompose your App
into smaller, non-overlapping pieces or disassociate player
from self
before calling the method.