可变地借用一个结构字段,同时在闭包中借用另一个

Mutably borrow one struct field while borrowing another in a closure

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

例如下面的代码:

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 方法是什么?

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

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

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

这个 recent blog post 显示了对此类问题非常有用的模式:

Sometimes, when I want to be very precise, I will write closures in a stylized way that makes it crystal clear what they are capturing. Instead of writing |v| ..., I first introduce a block that creates a lot of local variables, with the final thing in the block being a move closure (move closures take ownership of the things they use, instead of borrowing them from the creator). This gives complete control over what is borrowed and how. In this case, the closure might look like:

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

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

此代码的一个优点 属性 是 field2 的借用在不再使用后不会保留。