2016-04-29 43 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