4

我有下面的代码产生在其注释中标记的错误消息。我想我理解了这个信息:我想借用 parent 两次:一次是为了找到它的孩子,一次是作为孩子的参数(并且错误中的可变/不可变词不相关)。我必须证明Child它在修改时不会消失Parent。但我不知道该怎么做。除了接缝浪费外,我Rc<Child>什么都可以,所以我希望增加一些生命周期可以解决问题。

struct Parent {
    used: i32,
    child: Child,
}

struct Child {
    dummy: i32,
}

impl Child { 
    fn use_parent(&mut self, parent: &mut Parent) {
        // use both child and parent
        parent.used += self.dummy;
        self.dummy += 1;
    }
}
fn main() {
    let parent = Parent {
        used: 0,
        child: Child {
            dummy: 1
        }
    };
    //Error: cannot borrow immutable local variable `parent` as mutable
    parent.child.use_parent(&mut parent);
}
4

2 回答 2

1

并且错误中的可变/不可变词不相关

我不知道你为什么这么认为。可变性在 Rust中非常重要!例如,虽然允许您同时对不可变数据进行多次引用,但一次只能对可变数据进行一次引用。

首先,您需要修复 的可变性parent

let mut parent = // ...

然后,您会从该行中得到一个错误:

parent.child.use_parent(&mut parent);

当您运行此行时,您隐式可变地借用parentand child。这样做是为了让您可以调用use_parent,这需要&mut self.

但是,您试图获得第二个可变引用作为参数!这是一个禁忌,因为如果您被允许拥有多个别名可变引用,编译器将无法跟踪它并确保您不会破坏内存安全保证。

假设我删除了该行self.dummy+=1;,因此只有 1 个可变别名 - 我可以让它工作吗?

让我们看一下函数签名的一些变体

fn use_parent(&self, parent: &mut Parent)
// cannot borrow `parent` as mutable because `parent.child` is also borrowed as immutable

fn use_parent(&mut self, parent: &Parent)
// cannot borrow `parent` as immutable because `parent.child` is also borrowed as mutable

fn use_parent(&self, parent: &Parent)
// OK

正如我之前提到的,如果您对某事物有可变引用,则不允许您对同一事物有任何其他引用(可变与否)。

另外,请注意,方法的主体是什么并不重要!Rust 只检查被调用函数的签名来验证借用东西是否安全。

那么你如何尝试解决你的问题呢?最终,您正在尝试做一些编译器很难证明安全的事情。你想要一个可变链接图。我强烈建议阅读Rc 的模块文档,其中有一个正是这种父子关系的示例。

于 2015-03-03T14:15:04.037 回答
1

您收到错误消息的原因不同。你有一个不可变的变量parent,并试图为&mut它创建一个。修复你得到的

let mut parent = Parent {
    used: 0,
    child: Child {
        dummy: 1
    }
};
parent.child.use_parent(&mut parent);

以及相应的错误

<anon>:31:34: 31:40 error: cannot borrow `parent` as mutable more than once at a time
<anon>:31     parent.child.use_parent(&mut parent);
                                           ^~~~~~
<anon>:31:5: 31:17 note: previous borrow of `parent.child` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `parent.child` until the borrow ends
<anon>:31     parent.child.use_parent(&mut parent);
              ^~~~~~~~~~~~
<anon>:31:41: 31:41 note: previous borrow ends here
<anon>:31     parent.child.use_parent(&mut parent);
                                                 ^

你几乎得出了正确的结论。

我必须证明 Child 在修改 Parent 时不会消失

不完全的。你必须证明你永远不会有两个&mut或一个&mut和一个&给孩子。如果你有一个&mut给父母,你可以用它来&mut给孩子。因此,如果你有一个&mut给父母和一个&mut给孩子,你可以&mut给孩子两个。


我看到的唯一解决方案是将use函数移动到Parenttype 并访问childthrough self

impl Parent { 
    fn use_parent(&mut self) {
        // use both child and parent
        self.used += self.child.dummy;
        self.child.dummy += 1;
    }
}

处理您的评论:

不幸的是,该解决方案适用于这个简化的问题,但不适用于我的实际问题。父母有一个孩子的向量,它可能有深层嵌套的孙子。我不能只说 self.child

由于您不应该修改您的向量(并且不能,Rust 保护您),因为这会使对子项的引用无效,您可以将这些部分传递给您需要的函数,但没有直接父项的部分的孩子。

impl Child { 
    fn use_parent(&mut self, used: &mut i32) {
        // use both child and parent
        *used += self.dummy;
        self.dummy += 1;
    }
}

fn main() {
    let mut parent = Parent {
        used: 0,
        child: Child {
            dummy: 1
        }
    };
    // although both point to elements of the same structure
    // it is guaranteed at compile-time that they point to
    // non-overlapping parts
    let child = &mut parent.child;
    let used = &mut parent.used;
    child.use_parent(used);
}

不幸的是,我没有办法证明use_parent's 的参数指向同一个Parent对象的一部分。也许这可以用一生来完成,我不确定,但我会对此非常感兴趣。注意:Rc有同样的问题。

于 2015-03-03T14:22:41.087 回答