【问题标题】:Idiomatic Way to Handle Struct Fields that Reference the Parent处理引用父级的结构字段的惯用方式
【发布时间】:2021-09-28 04:04:15
【问题描述】:

在将应用程序从 Python 移植到 Rust 时,我遇到了这个问题。

如果我们有这样的类:

class Backend:
    def __init__(self, result_consumer=None):
        self.result_consumer = ResultConsumer(self, ..)
    
class ResultConsumer:
    def __init__(self, backend=None):
        self.backend=backend

ResultConsumer 经常调用像 self.backend.method() 这样的方法,而 Backend 也在调用像 self.result_consumer.method() 这样的方法。

在 Rust 中,你不能只使用结构字段来建立这种关系。

我尝试了一种使用泛型的方法(因为 ResultConsumer 应该支持多个后端)

struct ResultConsumer<B: Backend> {
    backend: Arc<B>,
}
struct Backend {
    result_consumer: ResultConsumer<Self>
}

在 Rust 中表示这种关系的最惯用的方式是什么?我的示例方法可行吗?

我特别问,因为当它编译时,我无法弄清楚如何在构建 result_consumer 字段中为 Backend 填充 ResultConsumer

【问题讨论】:

标签: rust


【解决方案1】:

如果我理解你,你可以使用类似下面的东西

struct ResultConsumer {
    backend: RefCell<Weak<Backend>>,
}
struct Backend {
    result_consumer: RefCell<Rc<ResultConsumer>>,
}

impl Backend {
    fn new() -> Rc<Backend> {
        println!("Backend::new");
        let mut b_rc = Rc::new(Backend {
            result_consumer: RefCell::new(Rc::new(ResultConsumer {
                backend: RefCell::new(Weak::new()),
            })),
        });

        *b_rc.result_consumer.borrow().backend.borrow_mut() = Rc::downgrade(&b_rc);
        b_rc
    }
}

【讨论】:

  • Rc 之一应该是Weak 以打破引用循环。
  • 不,它没有,你的代码drop (Backend::new()) 会泄漏:后端没有被释放,因为消费者指向它,消费者没有被释放,因为后端指向它。 Playground
  • @Jmb 谢谢你。已编辑
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-24
  • 2017-09-23
相关资源
最近更新 更多