Rust闭包(closure) 什么是闭包 Rust闭包的特点包括:
声明时使用 ||
替代 ()
将输入参数括起来。
函数体定界符({}
)对于单个表达式是可选的,其他情况必须加上。
有能力捕获外部环境的变量。
闭包是引用类型。
其具体使用方式为:
在rust
中,函数和闭包都是实现了Fn
、FnMut
或FnOnce
特质(trait
)的类型。任何实现了这三种特质其中一种的类型的对象,都是 可调用对象 ,都能像函数和闭包一样通过这样name()
的形式调用,()
在rust
中是一个操作符,操作符在rust
中是可以重载的。rust
的操作符重载是通过实现相应的trait
来实现,而()
操作符的相应trait
就是Fn
、FnMut
和FnOnce
,所以,任何实现了这三个trait
中的一种的类型,其实就是重载了()
操作符。
三种闭包的定义 虽然 Rust 无需类型说明就能在大多数时候完成变量捕获,但在编写函数时,这种模糊写法 是不允许的。当以闭包作为输入参数时,必须指出闭包的完整类型,它是通过使用以下 trait
中的一种来指定的。其受限制程度按以下顺序递减:
Fn
:表示捕获方式为通过引用(&T
)的闭包
FnMut
:表示捕获方式为通过可变引用(&mut T
)的闭包
FnOnce
:表示捕获方式为通过值(T
)的闭包
注意:顺序之所以是这样,是因为 &T
只是获取了不可变的引用,&mut T
则可以改变 变量,T
则是拿到了变量的所有权而非借用。
FnOnce 所有函数都至少能调用一次,所以全都会实现。FnOnce包含FnMut和FnOnce。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #[derive(Debug)] struct E { a: String , } impl Drop for E { fn drop (&mut self ) { println! ("destroyed struct E" ); } } fn fn_once <F>(func: F) where F: FnOnce () { println! ("fn_once begins" ); func(); println! ("fn_once ended" ); } fn main () { let e = E { a: "fn_once" .to_string() }; let f = || println! ("fn once closure calls: {:?}" , e); fn_once(f); println! ("main ended" ); }
打印结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 # 不加move fn_once begins fn once closure calls: E { a: "fn_once" } fn_once ended main ended destroyed struct E # move,不可复制类型必须移动,可复制类型将会复制给闭包,从而原始值不受影响 fn_once begins fn once calls: E { a: "fn_once" } destroyed struct E fn_once ended main ended
FnMut 对于那些不会移走匿名结构体中的变量的闭包实现。FnMut包含Fn。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #[derive(Debug)] struct E { a: String , } impl Drop for E { fn drop (&mut self ) { println! ("destroyed struct E" ); } } fn fn_mut <F>(mut func: F) where F: FnMut () { println! ("fn_mut begins" ); func(); func(); println! ("fn_mut ended" ); } fn main () { let mut e = E { a: "fn_once" .to_string() }; let f = || { println! ("FnMut closure calls: {:?}" , e); e.a = "fn_mut" .to_string(); }; fn_mut(f); println! ("main ended" ); }
打印结果如下:
1 2 3 4 5 6 fn_mut begins FnMut closure calls: E { a: "fn_once" } FnMut closure calls: E { a: "fn_mut" } fn_mut ended main ended destroyed struct E
Fn 对于那些不会修改匿名结构体中变量的闭包实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #[derive(Debug)] struct E { a: String , } impl Drop for E { fn drop (&mut self ) { println! ("destroyed struct E" ); } } fn fn_fn <F>(func: F) where F: Fn () { println! ("fn begins" ); func(); func(); println! ("fn ended" ); } fn main () { let e = E { a: "fn" .to_string() }; let f = || { println! ("Fn closure calls: {:?}" , e); }; fn_fn(f); println! ("main ended" ); }
打印结果如下:
1 2 3 4 5 6 fn begins Fn closure calls: E { a: "fn" } Fn closure calls: E { a: "fn" } fn ended main ended destroyed struct E