2015-09-04 47 views
4

試圖編譯這個節目,我陷在借檢查:易變借似乎活得比其範圍

use std::collections::BTreeMap; 

type Object<'a> = BTreeMap<&'a str, i32>; 

struct Root<'a>(Object<'a>); 

struct Sub<'a>(&'a mut Object<'a>, &'a str); 

impl<'a> Root<'a> { 
    fn borrow_mut(&'a mut self, data: &'a str) -> Sub<'a> { 
     Sub(&mut self.0, data) 
    } 

    fn borrow(&self) { 
     println!("{:?}", self.0); 
    } 
} 

fn main() { 
    let mut me = Root(Object::new()); 
    { 
     me.borrow_mut("data!"); 
    } 
    me.borrow(); 
} 

我得到:

error: cannot borrow `me` as immutable because it is also borrowed as mutable 

它看起來像可變借應該me.borrow()之前結束但檢查員堅持認爲它在main結束時結束。

要快速解釋什麼,我試圖完成:

  1. 讓家長結構來保存數據
  2. 使數據的子類別,並將其存儲在父
  3. 使用此建設者風格模式來做的MongoDB查詢

以上的防鏽圍欄代碼:http://is.gd/mLbBFG

+0

呃?現在這是意想不到的,可變借款應該是有限的。哦,除非你的一生影響它...... –

回答

4

你遇到了一生的問題。

有你的程序中多個不同的生命週期:

  • type Object<'a> = BTreeMap<&'a str, i32>; =>這是一個
  • &'a mut Object<'a> =>有多達兩個在這裏
  • struct Sub<'a>(&'a mut Object<'a>, &'a str); =>最多三個這裏

顯然,沒有理由提及Object<'a>具有相同的壽命比在BTreeMap以內的3210。不過,你告訴編譯器,你希望兩個生命週期都是一樣的!

當你寫:

struct Sub<'a>(&'a mut Object<'a>, &'a str); 

你告訴編譯器:

  • 參考的&strBTreeMap
  • 壽命的壽命Object<'_>
  • 壽命&str伴隨着Object<'_>

都是一樣的。

您對需求過度約束;結果沒有解決方案能夠滿足它們。

增加一個自由度就足夠了!我們只是做參考的壽命Object<'_>從這些&str的壽命不同漂浮:

struct Sub<'a, 'b: 'a>(&'a mut Object<'b>, &'b str); 

impl<'b> Root<'b> { 
    fn borrow_mut<'a>(&'a mut self, data: &'b str) -> Sub<'a, 'b> { 
     Sub(&mut self.0, data) 
    } 

    fn borrow(&self) { 
     println!("{:?}", self.0); 
    } 
} 

注意微妙的'b: 'a

  • Object<'b>包含的東西的參考,其壽命爲'b
  • 參考Object<'b>(表示爲'a)的壽命必須小於'b(否則您有一些死亡的參考?)

因此,我們說'b超過'a'b: 'a

就是這樣。簡單地放鬆這些需求可以讓編譯器允許你的代碼進行編譯。


注意,在一般情況下,如果你發現自己寫的東西像&'a &'a str你做錯了。如果你仔細想想,你會意識到,爲了創造一個參考,它必須首先。因此對對象必然的引用具有比對象本身更短的壽命(非常小)。

+0

非常感謝你!我一直想知道如何做到這一點。這是記錄在哪裏,我可以在哪裏瞭解更多? –

+0

[在Rust書中](https://doc.rust-lang.org/book/lifetimes.html)解釋了一般的生存期,但是我找不到那裏的''b:'a'語法被埋在某處)。 –

+0

對於任何好奇的人,我只在* nightly *文檔[這裏](https://doc.rust-lang.org/nightly/nomicon/subtyping.html)中找到關於此的文檔。 –