【问题标题】:Is there a way to initialize fields in two structs with a circular reference? [duplicate]有没有办法用循环引用初始化两个结构中的字段? [复制]
【发布时间】:2021-10-15 07:49:39
【问题描述】:

我有两个相互引用的结构。一旦初始化,它们在应用程序的剩余生命周期内都不会发生变异。

可以将它们包装在 MutexRwLock 或其他东西中,但最好不要在整个代码库中处理这些,只是为了初始化。

这是示例代码(不编译):

use std::sync::Arc;
struct First {
    second: Option<Second>,
}

struct Second {
    first: Option<Arc<First>>,
}

fn main() {
    let first = Arc::new(First { second: None });
    let mut second = Second { first: None };
    second.first = Some(first.clone());
    first.second = Some(second);
}

问题:

error[E0594]: cannot assign to data in an `Arc`
  --> src/main.rs:14:5
   |
14 |     first.second = Some(second);
   |     ^^^^^^^^^^^^ cannot assign
   |
   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc<First>`

这里发生了什么很清楚;无法分配给 first,因为它位于 Arc 内部,不允许内部可变性。

更改操作顺序并不能解决问题。

使用Arc::get_mut() 将不起作用,因为Arc 被克隆以存储在second.first 中。

那么,是否可以使用这种模式创建对象而不需要运行时锁定?

【问题讨论】:

    标签: rust


    【解决方案1】:

    您有两种选择,具体取决于您是否需要Sync

    Sync 需要一些同步结构,RwLock 应该这样做:

    use std::borrow::BorrowMut;
    use std::sync::RwLock;
    use std::sync::Arc;
    
    struct First {
        second: Option<Second>,
    }
    
    struct Second {
        first: Option<Arc<RwLock<First>>>,
    }
    
    fn main() {
        let first = Arc::new(RwLock::new(First { second: None }));
        let mut second = Second { first: None };
        second.first = Some(first.clone());
        let mut inner = first.write().unwrap();
        inner.second = Some(second);
    }
    

    Playground

    如果您不需要Sync,请使用Rc 代替ArcRefCell

    use std::rc::Rc;
    use std::cell::RefCell;
    
    struct First {
        second: Option<Second>,
    }
    
    struct Second {
        first: Option<Rc<RefCell<First>>>,
    }
    
    fn main() {
        let first = Rc::new(RefCell::new(First { second: None }));
        let mut second = Second { first: None };
        second.first = Some(first.clone());
        first.borrow_mut().second = Some(second);
    }
    

    Playground

    【讨论】:

    • @SvenMarnach,实际上,你是对的。它应该是Arc&lt;RwLock&gt;Rc&lt;RefCell&gt;
    猜你喜欢
    • 2021-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-17
    • 1970-01-01
    • 2020-03-10
    • 2022-01-22
    • 1970-01-01
    相关资源
    最近更新 更多