可变地借用一个结构字段,同时在闭包中借用另一个
Posted
技术标签:
【中文标题】可变地借用一个结构字段,同时在闭包中借用另一个【英文标题】:Mutably borrow one struct field while borrowing another in a closure 【发布时间】:2016-07-22 14:42:22 【问题描述】:我有一个包含两个字段的结构,我想使用另一个字段(不可变借用)修改一个字段(可变借用),但借用检查器出现错误。
比如下面的代码:
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 方法是什么?
【问题讨论】:
【参考方案1】:通常借用检查器可以区分结构的不同字段,但这在闭包(lambdas)中不起作用。
相反,借用闭包外的第二个字段:
let field2 = &strct.field2;
strct.field1.retain(|v| !field2.contains(v));
【讨论】:
Proposed RFC 2229 ("Closures Capture Disjoint Fields") 将使闭包的捕获语义更加智能,但它需要大量的工作和思考。【参考方案2】:这个recent blog post 显示了解决这类问题的一个非常有用的模式:
有时,当我想要非常精确时,我会以一种风格化的方式编写闭包,使它们捕获的内容一目了然。我没有写
|v| ...
,而是首先介绍一个创建大量局部变量的块,块中的最后一个东西是move
闭包(move
闭包拥有它们使用的东西,而不是借用它们来自创作者)。这可以完全控制借用的内容和方式。在这种情况下,闭包可能如下所示:
换句话说,借用是在闭包中正确定义的,并被移动到闭包中。这完全清楚地表明,它们的目的是为闭包提供借来的值。在原始问题的上下文中,模式如下所示:
strct.field1.retain(
let field2 = &strct.field2;
move |v| !field2.contains(v)
);
这段代码的一个很好的特性是,field2
的借用在不再使用后不会继续存在。
【讨论】:
现在我们有非词法生命周期。以上是关于可变地借用一个结构字段,同时在闭包中借用另一个的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Rust 中修复“.. 在循环的上一次迭代中可变地借用”?