我无法理解为什么特定模式没有编译。
当我移动一个变量然后在一个闭包之外重新分配它时,Rust会识别它,我认为正确地允许代码编译,但是当我尝试在一个不止一次运行的闭包中做同样的事情时它不会
fn main() {
let mut v = vec![1, 2, 3, 4];
v.into_iter().fold(0, |a, b| a + b);
v = vec![1, 2, 3, 4];
vec![1, 2, 3].into_iter().for_each(|x| {
v.into_iter().fold(x, |a, b| a + b);
v = vec![1, 2, 3, 4];
});
}
error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
--> src/main.rs:6:9
|
2 | let mut v = vec![1, 2, 3, 4];
| ----- captured outer variable
...
6 | v.into_iter().fold(x, |a, b| a + b);
| ^ cannot move out of captured outer variable in an `FnMut` closure
在我看来,重新分配给v
应该满足借用检查器,移动后不会访问任何变量。我错过了什么吗?
答案 0 :(得分:3)
正如@Shepmaster所提到的,修复方法是使用std::mem::replace
。
那么,有什么区别:
v.into_iter().fold(x, |a, b| a + b);
v = vec![1, 2, 3, 4];
和
let v_old = std::mem::replace(&mut v, vec![1, 2, 3, 4]);
v_old.into_iter().fold(x, |a, b| a + b);
用两个词来说:异常安全。
如果由于某种原因,表达式v.into_iter().fold(...)
会引起恐慌,则会将v
移出,并且永远不会执行下一个语句。
这在FnOnce
中完全可以接受,因为您永远不会再次调用该闭包,但在下次调用时FnMut
或Fn
中不能接受... <你会对v
做什么?
另一方面,使用std::mem::replace
,您首先交换 ,然后然后执行潜在的恐慌操作。如果操作确实发生恐慌,那么所有剩下的东西都会被移出&#34;是一个临时变量,无论如何都会在堆栈帧的末尾消失。没问题。
答案 1 :(得分:2)
重新分配给
v
应该满足借用检查器移动后不会访问任何变量
注意错误消息详细信息 - 没有开始的步骤:
cannot move out of captured outer variable in an `FnMut` closure
由于没有搬出,将东西搬回来是没有意义的。
相反,您可以通过mutable引用替换值并使用旧值:
fn main() {
let mut v = vec![1, 2, 3, 4];
vec![1, 2, 3].into_iter().for_each(move |x| {
let v_old = std::mem::replace(&mut v, vec![1, 2, 3, 4]);
v_old.into_iter().fold(x, |a, b| a + b);
});
}