Rust闭包(closure)

什么是闭包

Rust闭包的特点包括:

  • 声明时使用 || 替代 () 将输入参数括起来。
  • 函数体定界符({})对于单个表达式是可选的,其他情况必须加上。
  • 有能力捕获外部环境的变量。
  • 闭包是引用类型。

其具体使用方式为:

1
|val| val + x

​ 在rust中,函数和闭包都是实现了FnFnMutFnOnce特质(trait)的类型。任何实现了这三种特质其中一种的类型的对象,都是 可调用对象 ,都能像函数和闭包一样通过这样name()的形式调用,()rust中是一个操作符,操作符在rust中是可以重载的。rust的操作符重载是通过实现相应的trait来实现,而()操作符的相应trait就是FnFnMutFnOnce,所以,任何实现了这三个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() };
// 这样加个move,看看程序执行输出顺序有什么不同
// let f = move || println!("fn once calls: {:?}", e);
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