无法 hold/pass 将父级引用到组合对象

Unable to hold/pass reference of parent to the composition object

在 C++ 中,类似于 struct Astruct B 组成,B 的某些函数采用指向父对象 A 的指针。因此 A 的函数调用 B 的函数将简单地将 this 指针传递给它。我正在 Rust 中尝试这个,但未能让它工作 - 这就是我想要实现的目标:

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 中做到这一点的?

这行不通,因为您违反了可变别名要求 - 您试图同时可变地借用 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<...>,但它根本没有改变整个画面。)

这是 Rust 框架中的自然错误。假设 f 在此特定组合上的实现 X 重写了传递对象上的 composition 字段:

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

突然调用此方法的对象被销毁,self失效!

自然地,编译器会阻止你这样做即使你知道你不修改composition,因为这种知识不能静态编码(特别是考虑到这是一个特征方法,可以由任何有权访问你的特征的人来实现。

在这种情况下,您基本上有两种选择:

  • 重新表述问题,使其不再需要这样的架构,或者
  • 使用特殊的 language/library 构造来解决此类静态检查。

第二点是关于使用 Cell/RefCell 之类的东西(它们是安全的,即不需要 unsafe 块,但它们可能会在运行时出现恐慌 - 可能这些可以在你的情况下工作)或者,如果没有其他帮助,请使用原始指针和 unsafe 代码。但是,坦率地说,第一种选择通常更好:如果您根据编译器强制执行的所有权语义和别名规则设计代码,几乎总是生成的架构质量会好得多。