代码如下:
fn test(){
let mut numbers = vec![2];
let f = || {
for _ in numbers.iter(){
}
false
};
while false {
let res = f();
if res {
numbers.push(10);
}
}
}
错误是:
|
15 | let f = || {
| -- immutable borrow occurs here
16 | for _ in numbers.iter(){
| ------- first borrow occurs due to use of `numbers` in closure
...
22 | let res = f();
| - immutable borrow later used here
23 | if res {
24 | numbers.push(10);
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here
但是,如果我将while
关键字更改为if
,则可以对其进行编译。如何解决这个问题?我想循环调用匿名函数。
答案 0 :(得分:6)
通过用简单的不可变引用替换闭包,我们可以进一步简化您的示例
let mut numbers = vec![2];
let r = &numbers;
while false {
println!("{:?}", r);
numbers.push(10);
}
在这里我们得到这个错误:
error[E0502]: cannot borrow `numbers` as mutable because it is also borrowed as immutable
--> src/lib.rs:7:5
|
3 | let r = &numbers;
| -------- immutable borrow occurs here
...
6 | println!("{:?}", r); // use reference
| - immutable borrow later used here
7 | numbers.push(10);
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here
就像您的示例一样,将while
替换为if
可以使错误消失。为什么?
您可能已经知道重要的Rust规则:别名与变异性。它指出,在任何给定的时间,一个值要么可以多次不变地被任意借用,要么可以任意地一次精确地借用一次。
语句numbers.push(10)
临时(随机地)借用numbers
(仅适用于该语句)。但是我们还有r
,它是不可变的引用。为了使numbers.push(10)
工作,编译器必须确保当时没有其他借位。但是存在引用r
!此引用不能与numbers.push(10)
同时存在。
让我们首先看看if
的情况:
let mut numbers = vec![2];
let r = &numbers; // <------+ (creation of r)
// |
if false { // |
println!("{:?}", r); // <------+ (last use of r)
numbers.push(10);
}
虽然词法作用域意味着变量r
仅在函数末尾删除,但由于非词法生存期,编译器可以看到r
的最后一次使用是在{ {1}}行。然后,编译器可以在此行之后将println
标记为“死”。反过来,这意味着r
行中没有其他借用,一切正常。
对于循环情况?让我们想象一下循环迭代三遍:
numbers.push(10)
从这里可以看出,let mut numbers = vec![2];
let r = &numbers; // <------+ (creation of r)
// |
// First iteration // |
println!("{:?}", r); // |
numbers.push(10); // | <== oh oh!
// |
// Second iteration // |
println!("{:?}", r); // |
numbers.push(10); // |
// |
// Third iteration // |
println!("{:?}", r); // <------+ (last use of r)
numbers.push(10);
处于活动状态的时间与r
重叠(最后一个除外)。结果,编译器将产生错误,因为此代码违反了中心的Rust规则。
对于您的闭包情况,解释是相同的:闭包不可变地借用numbers.push(10)
,而numbers
使用该闭包。在循环情况下,编译器无法充分缩短关闭的“有效时间”,以确保它不与f();
的可变借位重叠。
如何解决?
好吧,您可以每次将push
传递给闭包:
numbers
之所以行之有效,是因为现在let mut numbers = vec![2];
let f = |numbers: &[i32]| {
for _ in numbers.iter(){
}
false
};
while false {
let res = f(&numbers);
if res {
numbers.push(10);
}
}
也是为numbers
语句而临时借用的。
您也可以使用f(&numbers);
作为其他答案,但这应该是最后的选择。
答案 1 :(得分:2)
不确定要完成什么,但是解决此问题的一种方法是使用products_tbl (product_id, product_manufacturer, product_name)
manufacturers_tbl (manufacturer_id, manufacturer_name)
(描述为in the std和{{3} }):
std::cell::RefCell
这里有一些经过调整的演示,它实际上可以执行以下操作:
use std::cell::RefCell;
fn test(){
let numbers = RefCell::new(vec![2]);
let f = || {
for _ in numbers.borrow().iter(){
}
false
};
while false {
let res = f();
if res {
numbers.borrow_mut().push(10);
}
}
}
输出:
use std::cell::RefCell; fn main() { test(); } fn test() { let numbers = RefCell::new(vec![0]); let f = || { for n in numbers.borrow().iter() { println!("In closure: {}", n); } println!(); true }; let mut i = 1; while i <= 3 { let res = f(); if res { numbers.borrow_mut().push(i); } i += 1; } println!("End of test(): {:?}", numbers.borrow()); }