对于这个基本问题真的很抱歉。
我正在尝试模拟 Web 服务器调用之类的东西并从外部范围捕获变量。
fn http_get(path: &str, f: &dyn Fn()) {
f();
}
fn main() {
let mut counter = 0;
http_get("/foo", &|| {
counter = counter + 1;
println!("/foo: {}", counter);
});
http_get("/bar", &|| {
counter = counter + 1;
println!("/bar: {}", counter);
});
}
Run Code Online (Sandbox Code Playgroud)
这会导致编译器错误cannot assign to 'counter', as it is a captured variable in a 'Fn' closure。
我知道我在一些基本的地方失败了,我有机会朝正确的方向推动吗?
首先,解释一下为什么这不起作用。
当您将您的内容转移counter到闭包中时,您基本上允许其他代码随时使用它。如果它只是一个闭包,您可以将move其放入闭包中,将值的所有权赋予内部函数,并且它将正常工作,包括突变,因为没有办法违反借用检查器规则。
现在,当您有两个必须使用相同值的闭包,并且您希望在counter两个闭包中都具有对 的可变引用时,借用检查器无法知道何时删除此可变引用。使用闭包的函数可以保存闭包供以后使用。然后,您将同时有两个对同一值的可变引用,这是借用检查器不允许的。
对于这种情况有几种解决方案。
RefCell. 它提供了内部可变性,因此即使您不传递对闭包的可变引用,您仍然可以改变 的值counter。在这种情况下,借用检查器规则在运行时进行检查。如果您的代码尝试同时获取两个可变引用,而不删除前一个引用,那么您的代码将会panic。fn http_get(path: &str, f: &dyn Fn()) {
f();
}
fn main() {
let counter = 0;
let r = std::cell::RefCell::new(counter);
http_get("/foo", &|| {
let mut counter = r.borrow_mut();
*counter = *counter + 1;
println!("/foo: {}", counter);
});
http_get("/bar", &move || {
let mut counter = r.borrow_mut();
*counter = *counter + 1;
println!("/bar: {}", counter);
});
}
Run Code Online (Sandbox Code Playgroud)
如果您需要跨越线程边界,您可以使用ArcandMutex正如@Zeppi 答案所建议的那样。
如果您使用多个线程并且需要改变的值就像 一样简单counter,那么您可能应该使用Arc和原子。它们允许从多个线程进行可变访问而无需锁定。
| 归档时间: |
|
| 查看次数: |
743 次 |
| 最近记录: |