Rust 闭包
Rust 的闭包可以近似看成一个包含捕获到的变量的结构体. 官方例子类似这样:
fn f<F : FnOnce() -> String> (g: F) {
println!("{}", g());
}
let mut s = String::from("foo");
let t = String::from("bar");
f(|| {
s += &t;
s
});
// Prints "foobar".
就会转成类似这样的结构体:
struct Closure<'a> {
s : String,
t : &'a String,
}
impl<'a> FnOnce<()> for Closure<'a> {
type Output = String;
fn call_once(self) -> String {
self.s += &*self.t;
self.s
}
}
闭包相关的 trait
在闭包里面有三个相关的 trait:FnOnce
, FnMut
, Fn
. 他们分别对应闭包的三种调用方式:占用所有权,可变引用,不可变引用。他们的定义分别这样:
pub trait FnOnce<Args>
where
Args: Tuple,
{
type Output;
// Required method
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
pub trait FnMut<Args>: FnOnce<Args>
where
Args: Tuple,
{
// Required method
extern "rust-call" fn call_mut(
&mut self,
args: Args
) -> Self::Output;
}
pub trait Fn<Args>: FnMut<Args>
where
Args: Tuple,
{
// Required method
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}
总结一下就是:
- 如果没有任何捕获变量,则实现 FnOnce
- 如果有捕获变量,并且会对捕获变量进行修改,则实现 FnMut
- 如果有捕获变量,但不会对捕获变量进行修改,则实现 Fn
- 编译器会把 FnOnce 当成 fn(T) 函数指针去看待
闭包实现的 Trait
闭包自身实现的 Trait:
- Sized
- Copy/Clone
- Sync/Send