2016-04-29 42 views
3

我正在尝试讨论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的引用,因为这会导致双向链接结构。但我应该可以借用一个参考并对其进行操作,不是吗?

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

我通过self作为参考receive解决了它。但是,如果我想appreceive中可变吗?我无法通过selfsender可变,因为我也借用player为可变。

回答

2

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

的确,它被转移到sender,但这不是这个消息的意思。由于Player::receive的价值为self,因此实际上必须分解app并将player移出,以便能够拨打receive。在那个时候,app现在是半成形的;它没有有效的价值player!如果receive试图访问app.player,它将使用无效的内存。

“不能搬出借来的内容” [...]因为我们已经借了参考self当我们走进sender功能。

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

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

你可以,只要你正在参考的东西完全形成在那一点上。又有两个提示在上面的论述:

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

    如果你不receive访问app.player,调整你的代码通过的其他组件App而不是整个容器。也许你有一些GameState这真的是你想要通过。

  2. 离开App处于无效状态

    您可以使用类似mem::replace放在一个不同Playerapp。然后它仍然完全(但不同)形成,并可以再次参考它。

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

但是如果我想要appreceive可变吗?

是!你会得到“不能一次借出*self多次”。然而,解决方案实际上基本相同!在调用该方法之前,将App分解为较小的,不重叠的部分或从self中取消关联player

2

的一种方式遵循Shepmaster's solution

解除关联playerself调用方法前。

是把playerOption

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

最后一个资源是使用RefCell