Pass self reference to contained object's function

情到浓时终转凉″ 提交于 2019-12-22 11:31:55

问题


I'm trying to grok Rust's ownership model. I'm trying to pass a reference to a containing object when calling a function on a struct.

Here's my struct:

pub struct Player {}

impl Player {
    pub fn receive(self, app: &App) {

    }
}

As you can see, receive expects a reference to an App object.

pub struct App {
    pub player: Player,
}

impl App {
    pub fn sender(self) {
        // how to call player.test() and pass self as a reference?
        self.player.receive(&self);
    }
}

The above code gives me "use of partially moved value: self". Which makes sense, because App has move semantics so the value was moved into the sender function when it was called.

If I change it so that sender takes a reference to self instead, I get "cannot move out of borrowed content", which also sort of makes sense because we've borrowed the reference to self when we went into the sender function.

So what do I do? I understand why I can't store a reference to App inside Player, since that would lead to a doubly-linked structure. But I should be able to borrow a reference and perform operations on it, no?

I couldn't find an answer in the official tutorial.

I solved it by passing self as a reference in receive. But what if I want app to be mutable in receive? I can't pass self as mutable in sender because I'm also borrowing player as mutable.


回答1:


because App has move semantics so the value was moved into the sender 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 the sender 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:

  1. If receive tried to access app.player

    If you don't access app.player in receive, restructure your code to pass the other components of App instead of the entire container. Maybe you have some GameState that is really what you want to pass.

  2. leaving the App in a invalid state

    You can use something like mem::replace to put in a different Player into app. 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 in receive?

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.




回答2:


One way to follow Shepmaster's solution

disassociate player from self 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.



来源:https://stackoverflow.com/questions/36936221/pass-self-reference-to-contained-objects-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!