【问题标题】:Pass self reference to contained object's function将自引用传递给包含对象的函数
【发布时间】:2016-04-29 10:42:16
【问题描述】:

我正在尝试了解 Rust 的所有权模型。在结构上调用函数时,我试图传递对包含对象的引用。

这是我的结构:

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,我会得到“无法移出借用的内容”,这也是有道理的,因为我们在何时借用了对 self 的引用我们进入了sender 函数。

那我该怎么办?我明白为什么我不能在Player 中存储对App 的引用,因为这会导致双链接结构。但是我应该可以借用一个引用并对其进行操作,不是吗?

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

我通过在receive 中传递self 作为参考解决了这个问题。但是如果我想让appreceive 中是可变的呢?我不能在sender 中将self 作为可变传递,因为我还借用player 作为可变。

【问题讨论】:

    标签: reference rust borrowing


    【解决方案1】:

    一种关注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

    【讨论】:

      【解决方案2】:

      因为App 具有移动语义,因此在调用sender 函数时会将值移动到该函数中。

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

      “无法移出借用的内容”[...],因为当我们进入 sender 函数时,我们已经借用了对 self 的引用。

      对,与上面有关。因为我们借用了一个App,所以我们不能将player 移出它,从而使App 处于无效状态。

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

      你可以,只要你引用的东西在那个时候完全形成。上面的阐述也有两个提示:

      1. 如果receive 尝试访问app.player

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

      2. 使App 处于无效状态

        您可以使用mem::replace 之类的东西将不同 Player 放入app。然后它仍然完全(但不同)形成并且可以再次引用它。

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

      但是如果我想让appreceive 中是可变的呢?

      是的!你会得到“不能一次多次借用 *self 为可变的”。但是,解决方案实际上基本相同!在调用该方法之前,将您的 App 分解为更小的、不重叠的部分,或者将 playerself 解除关联。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多