Rust 的 闭包(closures)是可以保存进变量或作为参数传递给其他函数的匿名函数。可以在一个地方创建闭包,然后在不同的上下文中执行闭包运算。不同于函数,闭包允许捕获调用者作用域中的值。我们将展示闭包的这些功能如何复用代码和自定义行为。

定义一个闭包

1
2
3
4
5
let expensive_closure = |num| {
println!("calculating slowly...");
thread::sleep(Duration::from_secs(2));
num
};

官方例子:

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
28
29
30
31
32
33
use std::thread;
use std::time::Duration;

fn main() {
generate_workout(25, 43);
}

// fn simulated_expensive_calculation(intensity: u32) -> u32 {
// println!("calculating slowly...");
// thread::sleep(Duration::from_secs(2));

// intensity
// }

fn generate_workout(intensity: u32, random_number: u32) {
let expensive_closure = |num| {
println!("calculating slowly...");
thread::sleep(Duration::from_secs(2));
num
};
// let expensive_result = simulated_expensive_calculation(intensity);

if intensity < 25 {
println!("Today, do {} pushups!", expensive_closure(intensity));
println!("Next, do {} situps!", expensive_closure(intensity));
} else {
if random_number == 3 {
println!("Take a break today! Remember to stay hydrated!");
} else {
println!("Today, run for {} minutes!", expensive_closure(intensity));
}
}
}

闭包类型推断和注解

在’|’符号中添加闭包参数的类型和 ‘{‘ 前添加返回值增加类型。这类似与函数中的类型注解。

1
2
3
4
5
let expensive_closure = |num: u32| -> u32 {
println!("calculating slowly...");
thread::sleep(Duration::from_secs(2));
num
};

几个行为相同的闭包:

1
2
3
4
fn  add_one_v1   (x: u32) -> u32 { x + 1 }
let add_one_v2 = |x: u32| -> u32 { x + 1 };
let add_one_v3 = |x| { x + 1 }; // 没有添加闭包参数类型和返回值类型,在没有使用时会编译出错
let add_one_v4 = |x| x + 1 ;

带有泛型和 Fn trait 的闭包

例子:

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use std::thread;
use std::time::Duration;

struct Cacher<T>
where
T: Fn(u32) -> u32,
{
calculation: T,
value: Option<u32>,
}

impl<T> Cacher<T>
where
T: Fn(u32) -> u32,
{
fn new(calculation: T) -> Cacher<T> {
Cacher {
calculation,
value: None,
}
}

fn value(&mut self, arg: u32) -> u32 {
match self.value {
Some(v) => {
if v == arg {
v
} else {
let v = (self.calculation)(arg);
self.value = Some(v);
v
}
}
None => {
let v = (self.calculation)(arg);
self.value = Some(v);
v
}
}
}
}

fn main() {
// generate_workout(22, 7);
let mut expensive_result = Cacher::new(|num| {
println!("calculating slowly...");
thread::sleep(Duration::from_secs(2));
num
});

println!("{}", expensive_result.value(13));
println!("{}", expensive_result.value(13));
println!("{}", expensive_result.value(13));
println!("{}", expensive_result.value(13));
println!("{}", expensive_result.value(3));
println!("{}", expensive_result.value(3));
println!("{}", expensive_result.value(3));
}

fn generate_workout(intensity: u32, random_number: u32) {
let mut expensive_result = Cacher::new(|num| {
println!("calculating slowly...");
thread::sleep(Duration::from_secs(2));
num
});

if intensity < 25 {
println!("Today, do {} pushups!", expensive_result.value(intensity));
println!("Next, do {} situps!", expensive_result.value(intensity));
} else {
if random_number == 3 {
println!("Take a break today! Remember to stay hydrated!");
} else {
println!(
"Today, run for {} minutes!",
expensive_result.value(intensity)
);
}
}
}