2016-09-26 58 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