2016-09-26 60 views
0

我有一些嵌套的結構體,不能創建父結構體的反向引用。一個example帶參考的嵌套結構

struct Foo<'a> { 
    parent: &'a Bar<'a>, 
} 

impl<'a> Foo<'a> { 
    fn new(parent: &'a Bar) -> Self { 
     Foo { parent: parent } 
    } 

    fn hello_world(&self) -> String { 
     self.parent.hello().to_owned() + " world" 
    } 
} 

struct Bar<'b> { 
    child: Option<Foo<'b>>, 
    data: &'static str, 
} 

impl<'b> Bar<'b> { 
    fn new() -> Self { 
     Bar { 
      child: None, 
      data: "hello", 
     } 
    } 

    fn hello(&self) -> &str { 
     self.data 
    } 

    fn get_foo(&self) -> Option<&Foo> { 
     self.child.as_ref() 
    } 
} 

fn main() { 
    let bar = Bar::new(); 
    assert_eq!("hello", bar.hello()); 
    match bar.get_foo() { 
     Some(foo) => assert_eq!("hello world", foo.hello_world()), 
     None =>(), 
    } 
} 

我怎麼能一起Bar參考替換NoneSome<Foo>?到目前爲止,我不確定這是可能的。

+6

你不行。請參閱http://stackoverflow.com/q/32300132/155423; http://stackoverflow.com/q/28833622/155423;以及關於循環參考的許多其他問題。 – Shepmaster

+0

@Shepmaster,這是真的嗎?我在[我的]示例中錯過了什麼(https://play.rust-lang.org/?gist=ec859a25cc772183411a2dfb10258cbe&version=stable&backtrace=0)?當我添加一行調試打印我的父母對象,我得到一個堆棧溢出錯誤,它試圖打印父/子的循環引用... –

+0

是的,這是真的;我不會故意騙人^ _ ^。 *參考*是'&Foo'。在你的評論中的例子中,你有一個'Arc',它不是一個簡單而無聊的參考,而是一個更智能的智能指針*。但是,您創建了一個無限循環(父節點指向父節點...)。通常,這就是['Weak'](https://doc.rust-lang.org/std/sync/struct.Weak.html)引用的用途。 – Shepmaster

回答

1

這不完全是您的示例的插入式解決方案,但我相信您可以使用ArcRwLock指定的方式創建「循環引用」。 API不完全相同(例如,parent是一個可選字段),我重命名了一些對象,它肯定更詳細,但是您的測試通過!

use std::sync::{Arc, RwLock}; 

#[derive(Debug, Clone)] 
struct Child { 
    parent: Option<Arc<RwLock<Parent>>> 
} 

impl Child { 
    fn new() -> Self { 
     Child { 
      parent: None 
     } 
    } 

    fn hello_world(&self) -> String { 
     let x = self.parent.as_ref().unwrap().clone(); 
     let y = x.read().unwrap(); 
     y.hello().to_owned() + " world" 
    } 
} 

#[derive(Debug, Clone)] 
struct Parent { 
    child: Option<Arc<RwLock<Child>>>, 
    data: &'static str 
} 

impl Parent { 
    fn new() -> Self { 
     Parent { 
      child: None, 
      data: "hello" 
     } 
    } 

    fn hello(&self) -> &str { 
     self.data 
    } 

    fn get_child(&self) -> Option<Arc<RwLock<Child>>> { 
     self.child.as_ref().map(|x| x.clone()) 
    } 


} 

fn main() { 
    let parent = Arc::new(RwLock::new(Parent::new())); 
    let child = Arc::new(RwLock::new(Child::new())); 

    parent.write().unwrap().child = Some(child.clone()); 
    child.write().unwrap().parent = Some(parent.clone()); 

    assert_eq!("hello", parent.read().unwrap().hello()); 

    { 
     let x = parent.read().unwrap(); 
     match x.get_child() { 
      Some(child) => { assert_eq!("hello world", child.read().unwrap().hello_world()); } 
      None => {}, 
     } 
    } 

} 
+0

啊,我完全錯過了它沒有OP的評論,所以我忘了提及你。確保你檢查出來;特別是關於'Weak'的一點,以及這個解決方案不使用**引用**的事實。 – Shepmaster

+0

@Shepmaster,哦,謝謝!但是,不是一種克隆的「Arc」是一種參照,至少在對這個詞的非嚴格理解中呢?此外,當然有些情況下,你會想要一個「無限循環」的引用(理解當然他們是危險的,並以某種方式使用它們會導致SO)? –

+0

是的,它是一種*參考*(* ** ** ** ** R **參考** C **),但如果有人問我如何處理「參考」,我wouldn不期望使用「Arc」。我不確定爲什麼有人會想要一個引用循環。請注意,一個循環會導致內存泄漏。 – Shepmaster