在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中如何做到这一点?
答案 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
代码。但是,坦率地说,第一个选项通常更好:如果您根据所有权语义和编译器强制执行的别名规则设计代码,那么几乎总是得到的架构质量会更好。