无法保持/传递父对象组合对象的引用

时间:2015-04-27 11:03:58

标签: rust

在C ++中,类似struct A的内容由struct 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中如何做到这一点?

1 个答案:

答案 0 :(得分:2)

这不起作用,因为您违反了可变别名要求 - 您试图同时可信地借用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的{​​{1}}实现重写了传递对象上的X字段:

composition

突然调用此方法的对象被破坏,impl T for X { fn f(&mut self, a: &mut A<X>) { a.composition = create_x_somehow(); } } 无效!

当然,即使您知道不修改self,编译器也会阻止您执行此操作,因为这种知识无法静态编码(特别是这是一种特质方法,任何有权访问您特征的人都可以实施。

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

  • 重新表述问题,因此它不再需要这样的架构,或
  • 使用特殊语言/库构造来解决此类静态检查。

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