【发布时间】:2018-09-17 03:25:57
【问题描述】:
我的目标是制作一个独立于底层数据结构工作的函数(特别是 Floodfill)。我试图通过传入两个闭包来做到这一点:一个用于查询,它不可变地借用一些数据,另一个用于变异,它可变地借用相同的数据。
示例(在the Rust Playground 上测试):
#![feature(nll)]
fn foo<F, G>(n: i32, closure: &F, mut_closure: &mut G)
where
F: Fn(i32) -> bool,
G: FnMut(i32) -> (),
{
if closure(n) {
mut_closure(n);
}
}
fn main() {
let mut data = 0;
let closure = |n| data == n;
let mut mut_closure = |n| {
data += n;
};
foo(0, &closure, &mut mut_closure);
}
错误:(调试,每晚)
error[E0502]: cannot borrow `data` as mutable because it is also borrowed as immutable
--> src/main.rs:16:27
|
15 | let closure = |n| data == n;
| --- ---- previous borrow occurs due to use of `data` in closure
| |
| immutable borrow occurs here
16 | let mut mut_closure = |n| {
| ^^^ mutable borrow occurs here
17 | data += n;
| ---- borrow occurs due to use of `data` in closure
18 | };
19 | foo(0, &closure, &mut mut_closure);
| -------- borrow later used here
我确实想出了一个解决方案,但它非常难看。如果我将闭包组合成一个并使用参数指定我想要的行为,它就会起作用:
// #![feature(nll)] not required for this solution
fn foo<F>(n: i32, closure: &mut F)
where
F: FnMut(i32, bool) -> Option<bool>,
{
if closure(n, false).unwrap() {
closure(n, true);
}
}
fn main() {
let mut data = 0;
let mut closure = |n, mutate| {
if mutate {
data += n;
None
} else {
Some(data == n)
}
};
foo(0, &mut closure);
}
如果没有这种奇怪的组合闭包方式,我有什么办法可以安抚借用检查器?
【问题讨论】:
-
我认为无论你得到什么答案都将是它自己的、特殊的、Rust 风格的怪异品牌。每个闭包都引用同一个对象(
data);无法保证它们不会同时被调用,这可能会导致未定义且明显非 Rust 的行为。当然,不用像 Mutex 之类的特殊包装器。 -
可能有重复的问题,所以只是评论。在有不可变引用的情况下改变一个值是未定义的行为。你可以use
RefCell来避免它。
标签: rust closures borrow-checker