将自引用传递给包含对象的函数

时间:2016-04-29 10:42:16

标签: reference rust borrowing

我试图了解Rust的所有权模式。我在调用struct上的函数时尝试传递对包含对象的引用。

这是我的结构:

pub struct Player {}

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

    }
}

如您所见,receive需要引用App对象。

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);
    }
}

以上代码为我提供了使用部分移动的值:self"。这是有道理的,因为App具有移动语义,所以当调用它时,值被移动到sender函数中。

如果我更改它以便sender引用self,我会得到"无法移出借来的内容",这也是有道理的,因为我们&# 39;当我们进入self函数时,我借用了对sender的引用。

那我该怎么办?我理解为什么我无法在App内存储Player的引用,因为这会导致双重链接结构。但是我应该可以借用一个引用并对它进行操作,不是吗?

我在官方教程中找不到答案。

我通过在self中传递receive作为参考来解决它。但是,如果我希望appreceive可变,该怎么办?我无法在self中将sender作为可变对象,因为我还借用player作为可变对象。

2 个答案:

答案 0 :(得分:3)

关注Shepmaster's solution

的一种方法
  在调用方法之前,

playerself取消关联。

是将player放入Option

impl App {
    pub fn sender(&mut self) {
        let mut player = self.player.take();
        player.receive(&mut self);
        self.player = Some(player);
    }
}

最后一项资源是使用RefCell

答案 1 :(得分:2)

  

因为App具有移动语义,所以在调用它时,值被移动到sender函数中。

确实已将其移至sender,但这不是此消息的内容。由于Player::receive按值self获取,因此您实际上必须分解app并将player移出其中才能调用receive。在那个时间点,app现在是半成形的;它没有player的有效值!如果receive尝试访问app.player,则会使用无效内存。

  

"无法摆脱借来的内容" [...]因为我们在进入self函数时借用了对sender的引用。

对,这与上述联系在一起。由于我们正在借用App,因此我们无法移动player,导致App处于无效状态。

  

我应该可以借用一个引用并对它执行操作,不是吗?

你可以,只要你参考的东西完全在那时形成。上述论述中还有两个提示:

  1.   

    如果receive试图访问app.player

    如果您无法访问app.player中的receive,请重新构建代码以传递App的其他组件,而不是整个容器。也许你有一些GameState,这是你想要传递的。

  2.   

    App置于无效状态

    您可以使用mem::replace之类的内容将不同的 Player放入app。然后它仍然完全(但不同)形成,并可以再次参考它。

  3. 当然,更实际的解决方案是更改为接受引用(&self)。

      

    但是,如果我希望app中的receive可变,那该怎么办?

    烨!你得到的#{1}不能一次性地多次使用*self和#34;然而,解决方案实际上基本相同!在调用方法之前,将App分解为较小的,不重叠的部分或将playerself取消关联。