2015-04-27 27 views
3

在C++中,類似於struct A的東西由struct B組成,並且B的某些函數將一個指向父對象A的指針。所以調用B函數的A函數將簡單地將this指針傳遞給它。我想這鏽,但未能得到它的工作 - 這是我想達到什麼:無法保持/傳遞父對象到構圖對象的引用

struct A<Type: T> { 
    composition: Type, 
    value: usize, 
} 

impl<Type> A<Type> where Type: T { 
    fn new(obj: Type) -> A<Type> { 
     A { 
      composition: obj, 
      value: 999, 
     } 
    } 

    fn f(&mut self) { 
     println!("Value: {:?}", self.value); 
    } 

    fn call(&mut self) { 
     self.composition.f(&mut self); 
    } 
} 

trait T { 
    fn f(&mut self, &mut A<Self>); 
} 

struct B { 
    value: usize, 
} 

impl B { 
    fn new() -> B { 
     B { value: 0, } 
    } 
} 

impl T for B { 
    fn f(&mut self, parent: &mut A<B>) { 
     println!("B::f"); 
     parent.f(); 
    } 
} 

fn main() { 
    let objA = A::new(B::new()); 

    // I want call sequence -> A::call() -> B::f() -> A::f() 
    objA.call(); 
} 

注意,我需要在可變性的所有功能雖然例如上面也許看起來&mut self在大多數函數參數沒有多大意義。它在Rust中如何做到這一點?

回答

2

,因爲你違反了可變的別名要求這可不行 - 你試圖借用性情不定地和A其同時子:

self.composition.f(self); 
// roughtly equivalent to: 
let c = &mut self.composition; // borrow substructure 
c.f(self /* borrow self */); 

(我已經去除了明確&mut self,因爲它是不正確(因爲它給你&mut &mut A<...>,但它不會改變整個畫面都沒有。)

這是拉斯特框架自然誤差。假設f實現在這個特別的成分X改寫上個composition場Ë傳遞的對象:

impl T for X { 
    fn f(&mut self, a: &mut A<X>) { 
     a.composition = create_x_somehow(); 
    } 
} 

突然,這個方法被調用的被破壞的對象,self無效!

當然,編譯器會阻止您這樣做即使你知道您不要修改composition,因爲這種類型的知識,不能靜態地編碼(尤其是考慮到這是可以通過實施的特質方法任何人都可以訪問你的特質)。

你有這種情況主要有兩個選擇:

  • 重新制定的問題,所以它不需要這樣的架構了,或者
  • 使用特殊的語言/庫構建來解決這樣的靜態檢查。

第二點是關於使用這樣的事情Cell/RefCell(他們是安全的,即不需要unsafe塊,但他們可以在運行時驚慌 - 也許這些都可以在你的情況下工作),如果沒有,或者別的幫助,下降到原始指針和unsafe代碼。但坦率地說,第一個選項通常更好:如果您根據編譯器強制實施的所有權語義和別名規則設計代碼,則幾乎總是得到的架構質量會更好。