前言
本文主要覆盖闭包的基础知识点。
基本语法
1
|
let add = |a:i32, b:i32| ->i32 { return a + b; };
|
闭包的返回值和参数类型是可以省略的:
1
|
let add = |a, b| { return a + b; };
|
和普通函数一样,最后的 return 也可以省略:
1
|
let add = |a, b| { a + b };
|
如果只有一条语句大括号也可以省略:
1
|
let add = |a, b| a + b;
|
变量捕获
Rust 中默认变量捕捉是根据使用自动选择捕捉形式。一般可以理解为 3 种:&T,&mut T。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
struct T(i32);
fn by_value(_: T) {}
fn by_mut(_: &mut T) {}
fn by_ref(_: &T) {}
fn main() {
let x = T(1);
let y = T(2);
let mut z = T(3);
let closure = || {
by_value(x);
by_ref(&y);
by_mut(&mut z);
};
closure();
}
|
有时闭包的生命周期会超过原本的函数范围:
1
2
3
4
5
6
7
8
9
10
|
fn return_closure_error()->impl Fn()->i32 {
let a = 1;
|| a // error
}
fn return_closure()->impl Fn()->i32 {
let a = 1;
move || a
}
|
对于这种情况我们可以使用 move 关键字全部通过 by value 方式捕捉。
不过细究之下还会有个小问题:
1
2
3
4
5
6
7
|
fn main() {
let c = 3;
let add = |a| move |b| a + b + c;
println!("{}", add(1)(2));
}
|
我们不想通过 by value 的形式捕捉 c 怎么办呢?其实只要用 by value 形式捕获 c 的引用就可以了:
1
2
3
4
5
6
7
|
fn main() {
let c = &3;
let add = |a| move |b| a + b + c;
println!("{}", add(1)(2));
}
|
这种情况可能在上例中有点无病呻吟的意思,不过结合多线程的场景就能理解。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
use std::sync::Arc;
use std::thread;
fn main() {
let states: Vec<_> = (0..10i32).collect();
let shared_states = Arc::new(states);
for _ in 0..10 {
let shared = shared_states.clone();
thread::spawn(move || {
let _ = &shared;
});
}
}
|
我们肯定不希望直接把状态的所有权直接转移进特定线程,所以可以变通一下搞一个线程安全的 Arc 引用数据,然后 clone 它把它传进去。