我有一个包含两个字段的结构,我想使用另一个字段(不可变借用)修改一个字段(可变借用),但是我从借用检查器得到一个错误。
例如,以下代码:
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方法是什么?
通常借用检查器可以区分结构的不同字段,但这在闭包(lambdas)中不起作用。
相反,借用闭包之外的第二个字段:
let field2 = &strct.field2;
strct.field1.retain(|v| !field2.contains(v));
这个recent blog post为这类问题展示了一个非常有用的模式:
有时候,当我想要非常精确的时候,我会以一种程式化的方式编写闭包,这使得它们清晰地捕捉到了什么。而不是写
|v| ...
,我首先介绍一个创建了很多局部变量的块,块中的最后一个东西是move
闭包(move
闭包取得他们使用的东西的所有权,而不是从创建者那里借用它们)。这样可以完全控制借来的东西和方法。在这种情况下,闭包可能看起来像:
换句话说,借用与封闭物一起限定并移入封闭物中。这清楚地表明他们的目的是为封闭提供借来的价值。在原始问题的上下文中,模式看起来像这样:
strct.field1.retain({
let field2 = &strct.field2;
move |v| !field2.contains(v)
});
这段代码的一个很好的属性是field2
的借用在不再使用之后不会留下来。