19

我有一个包含两个字段的结构,我想使用另一个字段(不可变借用)修改一个字段(可变借用),但是借用检查器出现错误。

例如,下面的代码:

struct Struct {
    field1: Vec<i32>,
    field2: Vec<i32>,
}

fn main() {
    let mut strct = Struct {
        field1: vec![1, 2, 3],
        field2: vec![2, 3, 4],
    };

    strct.field1.retain(|v| !strct.field2.contains(v));

    println!("{:?}", strct.field1);
}

给出以下错误:

error[E0502]: cannot borrow `strct.field1` as mutable because it is also borrowed as immutable
  --> src/main.rs:12:5
   |
12 |     strct.field1.retain(|v| !strct.field2.contains(v));
   |     ^^^^^^^^^^^^^------^---^^-----^^^^^^^^^^^^^^^^^^^^
   |     |            |      |    |
   |     |            |      |    first borrow occurs due to use of `strct` in closure
   |     |            |      immutable borrow occurs here
   |     |            immutable borrow later used by call
   |     mutable borrow occurs here

在闭包中使用另一个字段更新一个字段的 Rust 方法是什么?

4

2 回答 2

25

通常借用检查器可以区分结构的不同字段,但这在闭包(lambdas)中不起作用。

相反,借用闭包外的第二个字段:

let field2 = &strct.field2;
strct.field1.retain(|v| !field2.contains(v));
于 2016-04-02T22:06:53.190 回答
3

这篇最近的博客文章展示了解决此类问题的一个非常有用的模式:

有时,当我想要非常精确时,我会以一种风格化的方式编写闭包,使它们捕获的内容一目了然。我没有写|v| ...,而是首先介绍一个创建许多局部变量的块,该块中的最后一个东西是一个move闭包(move闭包拥有它们使用的东西的所有权,而不是从创建者那里借用它们)。这可以完全控制借用的内容和方式。在这种情况下,闭包可能如下所示:

换句话说,借用是在闭包中正确定义的,并移动到闭包中。这完全清楚地表明,它们的目的是为闭包提供借来的值。在原始问题的上下文中,模式如下所示:

strct.field1.retain({
    let field2 = &strct.field2;
    move |v| !field2.contains(v)
});

这段代码的一个很好的特性是借用 的field2不再使用后不会继续存在。

于 2018-05-03T08:04:46.827 回答