fcr*_*r79 3 closures move mutable rust borrowing
我有以下代码片段:
fn f<T: FnOnce() -> u32>(c: T) {
println!("Hello {}", c());
}
fn main() {
let mut x = 32;
let g = move || {
x = 33;
x
};
g(); // Error: cannot borrow as mutable. Doubt 1
f(g); // Instead, this would work. Doubt 2
println!("{}", x); // 32
}
Run Code Online (Sandbox Code Playgroud)
疑问1
我什至无法运行一次。
疑问2
...但我可以根据需要多次调用该闭包,只要我通过f
. 有趣的是,如果我声明它FnMut
,我会得到与疑问 1 相同的错误。
疑点3
和特征定义self
中指的是什么?这就是关闭本身吗?还是环境?例如,来自文档:Fn
FnMut
FnOnce
pub trait FnMut<Args>: FnOnce<Args> {
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}
Run Code Online (Sandbox Code Playgroud)
Fn*
要理解闭包的实际工作原理,需要一些有关特征族的基础知识。你有以下特点:
FnOnce
,顾名思义,只能运行一次。如果我们查看文档页面,我们会发现特征定义几乎与您在问题中指定的定义相同。但最重要的是:“call”函数采用self
,这意味着它消耗实现 的对象FnOnce
,因此与任何采用 aself
作为参数的特征函数一样,它获取该对象的所有权。FnMut
,它允许捕获的变量发生突变,或者换句话说,它需要&mut self
。这意味着,当您创建move || {}
闭包时,它会将您引用的闭包范围之外的任何变量移动到闭包的对象中。闭包的对象具有不可命名的类型,这意味着它对于每个闭包都是唯一的。这确实迫使用户采用某种可变版本的闭包,所以&mut impl FnMut() -> ()
或者mut x: impl FnMut() -> ()
Fn
,通常被认为是最灵活的。这允许用户获取实现该特征的对象的不可变版本。此特征的“调用”函数的函数签名是这三个函数中最容易理解的,因为它只需要对闭包的引用,这意味着您在传递或调用它时无需担心所有权。针对您个人的疑虑:
move
某些东西放入闭包中时,该变量现在由闭包拥有。本质上,编译器生成的内容类似于以下伪代码:struct g_Impl {
x: usize
}
impl FnOnce() -> usize for g_Impl {
fn call_once(mut self) -> usize {
}
}
impl FnMut() -> usize for g_Impl {
fn call_mut(&mut self) -> usize {
//Here starts your actual code:
self.x = 33;
self.x
}
}
//No impl Fn() -> usize.
Run Code Online (Sandbox Code Playgroud)
默认情况下它会调用FnMut() -> usize
实现。
Copy
与它们捕获的每个变量的长度一样Copy
,这意味着生成的闭包将被复制到 中f
,因此f
最终会获取Copy
其中的 a 。当您将 for 的定义更改f
为 take anFnMut
时,您会收到错误,因为您面临与疑问 1 类似的情况:您试图调用一个函数,该函数&mut self
在您声明参数为c: T
时而不是mut c: T
or c: &mut T
,或者其中有资格&mut self
在眼中FnMut
。self
参数是闭包本身,它捕获或移动了一些变量到它自己中,所以它现在拥有它们。 归档时间: |
|
查看次数: |
1582 次 |
最近记录: |