1. 函数定义与调用

1.1 基本函数定义

Rust 使用 fn 关键字定义函数,函数名使用 snake_case(小写 + 下划线)风格。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 最简单的函数:无参数,无返回值
fn say_hello() {
println!("Hello, Rust!");
}

// 带参数的函数
fn greet(name: &str) {
println!("你好,{}!", name);
}

// 带返回值的函数
fn add(a: i32, b: i32) -> i32 {
a + b // 最后一个表达式作为返回值(无分号)
}

fn main() {
say_hello();
greet("张三");

let result = add(3, 4);
println!("3 + 4 = {}", result);
}

1.2 函数声明顺序

Rust 中函数声明的顺序无关紧要,只要在同一个作用域内即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fn main() {
// 可以调用在后面定义的函数
let result = multiply(6, 7);
println!("6 * 7 = {}", result);

// 调用嵌套函数
inner_function();

// 函数可以定义在 main 内部
fn inner_function() {
println!("我是内部函数");
}
}

// 函数定义在 main 之后也没问题
fn multiply(a: i32, b: i32) -> i32 {
a * b
}

1.3 函数命名规范

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
// 函数名使用 snake_case
fn calculate_area(width: f64, height: f64) -> f64 {
width * height
}

// 构造函数通常命名为 new
struct Rectangle {
width: f64,
height: f64,
}

impl Rectangle {
fn new(width: f64, height: f64) -> Self {
Rectangle { width, height }
}

fn area(&self) -> f64 {
self.width * self.height
}

// 谓词函数(返回 bool)通常以 is_ / has_ / can_ 开头
fn is_square(&self) -> bool {
(self.width - self.height).abs() < f64::EPSILON
}
}

fn main() {
let area = calculate_area(5.0, 3.0);
println!("面积: {}", area);

let rect = Rectangle::new(4.0, 4.0);
println!("矩形面积: {}", rect.area());
println!("是正方形: {}", rect.is_square());
}

2. 参数与返回值

2.1 参数类型标注

Rust 函数的参数必须显式标注类型。

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
// 基本类型参数
fn print_number(x: i32) {
println!("数字: {}", x);
}

// 多个参数
fn print_sum(a: i32, b: i32) {
println!("{} + {} = {}", a, b, a + b);
}

// 不同类型参数
fn describe(name: &str, age: u32, height: f64) {
println!("{} 今年 {} 岁,身高 {:.1} 厘米", name, age, height);
}

// 引用参数
fn print_length(s: &String) {
println!("长度: {}", s.len());
}

// 可变引用参数
fn append_exclamation(s: &mut String) {
s.push_str("!");
}

// 切片参数(推荐用 &str 代替 &String)
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &byte) in bytes.iter().enumerate() {
if byte == b' ' {
return &s[..i];
}
}
s
}

fn main() {
print_number(42);
print_sum(3, 4);
describe("李四", 25, 175.5);

let mut s = String::from("Hello");
print_length(&s);
append_exclamation(&mut s);
println!("修改后: {}", s);

let word = first_word("Hello World");
println!("第一个单词: {}", word);
}

2.2 返回值类型

使用 -> 指定返回值类型。没有返回值时,隐式返回 ()(unit 类型)。

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
// 返回 i32
fn square(x: i32) -> i32 {
x * x
}

// 返回 String
fn create_greeting(name: &str) -> String {
format!("你好,{}!", name)
}

// 返回 bool
fn is_even(n: i32) -> bool {
n % 2 == 0
}

// 返回 Option
fn divide(a: f64, b: f64) -> Option<f64> {
if b == 0.0 {
None
} else {
Some(a / b)
}
}

// 返回 Result
fn parse_number(s: &str) -> Result<i32, std::num::ParseIntError> {
s.parse::<i32>()
}

// 无返回值(隐式返回 ())
fn print_and_do_nothing(msg: &str) {
println!("{}", msg);
// 隐式返回 ()
}

// 显式返回 ()
fn explicit_unit() -> () {
println!("显式返回 unit");
}

fn main() {
println!("5^2 = {}", square(5));
println!("{}", create_greeting("Rust"));
println!("4 是偶数: {}", is_even(4));

match divide(10.0, 3.0) {
Some(result) => println!("10 / 3 = {:.4}", result),
None => println!("除零错误"),
}

match divide(10.0, 0.0) {
Some(result) => println!("结果: {}", result),
None => println!("不能除以零"),
}

match parse_number("42") {
Ok(n) => println!("解析成功: {}", n),
Err(e) => println!("解析失败: {}", e),
}

match parse_number("abc") {
Ok(n) => println!("解析成功: {}", n),
Err(e) => println!("解析失败: {}", e),
}

print_and_do_nothing("hello");
explicit_unit();
}

2.3 提前返回(return 关键字)

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
fn find_first_negative(numbers: &[i32]) -> Option<i32> {
for &num in numbers {
if num < 0 {
return Some(num); // 提前返回
}
}
None // 最后的表达式作为默认返回值
}

fn validate_age(age: i32) -> Result<i32, String> {
if age < 0 {
return Err(String::from("年龄不能为负数"));
}
if age > 150 {
return Err(String::from("年龄不合理"));
}
Ok(age) // 最后一行不需要 return
}

fn main() {
let numbers = [3, 7, -2, 5, -8, 1];
match find_first_negative(&numbers) {
Some(n) => println!("第一个负数: {}", n),
None => println!("没有负数"),
}

for age in [-5, 25, 200] {
match validate_age(age) {
Ok(a) => println!("有效年龄: {}", a),
Err(e) => println!("无效年龄 {}: {}", age, e),
}
}
}

3. 表达式作为返回值

Rust 函数体中最后一个表达式(无分号)自动成为返回值。

3.1 函数返回表达式

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
// 无分号的表达式作为返回值
fn add(a: i32, b: i32) -> i32 {
a + b // 注意:没有分号!这是返回值
}

// 如果加了分号,就变成了语句,返回 ()
// fn add_wrong(a: i32, b: i32) -> i32 {
// a + b; // 编译错误!这是语句,返回 (),与声明的 i32 不匹配
// }

// 代码块也是表达式
fn complex_calculation(x: i32) -> i32 {
let intermediate = {
let a = x * 2;
let b = a + 10;
b * b // 代码块的返回值
};
intermediate - x // 函数的返回值
}

// if 表达式作为返回值
fn absolute_value(x: i32) -> i32 {
if x >= 0 { x } else { -x }
}

// match 表达式作为返回值
fn describe_number(n: i32) -> &'static str {
match n {
0 => "零",
1..=9 => "个位正数",
-9..=-1 => "个位负数",
_ => "多位数",
}
}

fn main() {
println!("add(3, 4) = {}", add(3, 4));
println!("complex(5) = {}", complex_calculation(5));
println!("abs(-7) = {}", absolute_value(-7));
println!("describe(42) = {}", describe_number(42));
}

3.2 return 与表达式的区别

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
fn max_v1(a: i32, b: i32) -> i32 {
// 使用 return 关键字(显式返回)
if a > b {
return a;
}
return b;
}

fn max_v2(a: i32, b: i32) -> i32 {
// 使用表达式(更 Rust 风格)
if a > b { a } else { b }
}

fn max_v3(a: i32, b: i32) -> i32 {
// 混合使用:中间用 return 提前退出,最后用表达式
if a == b {
return 0; // 特殊情况提前返回
}
if a > b { a } else { b } // 正常情况用表达式返回
}

fn main() {
println!("max_v1(3, 5) = {}", max_v1(3, 5));
println!("max_v2(3, 5) = {}", max_v2(3, 5));
println!("max_v3(5, 5) = {}", max_v3(5, 5));
}

4. 多返回值

Rust 使用元组实现多返回值。

4.1 使用元组返回多个值

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
fn min_max(list: &[i32]) -> (i32, i32) {
let mut min = list[0];
let mut max = list[0];

for &item in &list[1..] {
if item < min {
min = item;
}
if item > max {
max = item;
}
}

(min, max) // 返回元组
}

fn divide_with_remainder(dividend: i32, divisor: i32) -> (i32, i32) {
let quotient = dividend / divisor;
let remainder = dividend % divisor;
(quotient, remainder)
}

fn statistics(data: &[f64]) -> (f64, f64, f64) {
let len = data.len() as f64;
let sum: f64 = data.iter().sum();
let mean = sum / len;

let variance = data.iter()
.map(|&x| (x - mean).powi(2))
.sum::<f64>() / len;

let std_dev = variance.sqrt();

(mean, variance, std_dev)
}

fn main() {
let numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3];

// 解构元组
let (min, max) = min_max(&numbers);
println!("最小值: {}, 最大值: {}", min, max);

let (quotient, remainder) = divide_with_remainder(17, 5);
println!("17 / 5 = {} 余 {}", quotient, remainder);

let data = [85.0, 92.0, 78.0, 90.0, 88.0, 95.0, 82.0];
let (mean, variance, std_dev) = statistics(&data);
println!("平均值: {:.2}", mean);
println!("方差: {:.2}", variance);
println!("标准差: {:.2}", std_dev);
}

4.2 使用结构体返回(更清晰)

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
#[derive(Debug)]
struct ParsedUrl {
protocol: String,
host: String,
port: u16,
path: String,
}

fn parse_url(url: &str) -> Option<ParsedUrl> {
// 简化的 URL 解析
let url = url.trim();

let (protocol, rest) = url.split_once("://").unwrap_or(("http", url));

let (host_port, path) = rest.split_once('/').unwrap_or((rest, ""));

let (host, port) = if let Some((h, p)) = host_port.split_once(':') {
(h.to_string(), p.parse::<u16>().unwrap_or(80))
} else {
(host_port.to_string(), if protocol == "https" { 443 } else { 80 })
};

Some(ParsedUrl {
protocol: protocol.to_string(),
host,
port,
path: format!("/{}", path),
})
}

fn main() {
let urls = [
"https://example.com/api/data",
"http://localhost:8080/index.html",
"https://rust-lang.org:443/learn",
];

for url in &urls {
if let Some(parsed) = parse_url(url) {
println!("{:#?}", parsed);
println!();
}
}
}

5. 发散函数(Never Type !)

发散函数是永远不会返回的函数,其返回类型为 !(never type)。

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
// panic! 是一个发散表达式
// fn diverging() -> ! {
// panic!("这个函数永远不会返回");
// }

// 无限循环也是发散的
fn forever() -> ! {
loop {
// 永远不会结束
std::thread::sleep(std::time::Duration::from_secs(1));
}
}

// process::exit 也是发散的
fn exit_program() -> ! {
std::process::exit(1);
}

fn main() {
// ! 类型可以被强制转换为任何其他类型
// 这在 match 和 if 中非常有用

let x: Option<i32> = Some(42);

// unwrap 的简化实现思路:
// match 的每个分支必须返回相同类型
// panic! 返回 !,可以匹配任何类型
let value = match x {
Some(v) => v, // 返回 i32
None => panic!("无值"), // ! 可以转换为 i32
};
println!("value = {}", value);

// 在 loop 中使用
let number = loop {
let input = "42"; // 模拟用户输入
match input.parse::<i32>() {
Ok(n) => break n, // 返回 i32
Err(_) => continue, // continue 返回 !,可以匹配 i32
}
};
println!("number = {}", number);

// todo!() 和 unimplemented!() 也是发散的
// 它们在开发中用作占位符
fn future_feature() -> String {
todo!("这个功能还没实现") // 返回 !,编译通过
}

// 不要调用 future_feature(),会 panic
// future_feature();

println!("发散函数演示完成");
}

6. 函数指针(fn 类型)

函数指针允许将函数作为值传递。

6.1 基本函数指针

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
// 普通函数
fn add(a: i32, b: i32) -> i32 { a + b }
fn subtract(a: i32, b: i32) -> i32 { a - b }
fn multiply(a: i32, b: i32) -> i32 { a * b }

fn main() {
// 函数指针类型:fn(参数类型) -> 返回类型
let operation: fn(i32, i32) -> i32 = add;
println!("operation(3, 4) = {}", operation(3, 4)); // 7

// 可以重新赋值为另一个函数(签名必须匹配)
let operation: fn(i32, i32) -> i32 = subtract;
println!("operation(10, 3) = {}", operation(10, 3)); // 7

// 存储在数组或 Vec 中
let operations: [fn(i32, i32) -> i32; 3] = [add, subtract, multiply];
let names = ["加", "减", "乘"];

for (op, name) in operations.iter().zip(names.iter()) {
println!("5 {} 3 = {}", name, op(5, 3));
}

// 函数指针作为参数传递
apply_operation(10, 5, add, "加法");
apply_operation(10, 5, subtract, "减法");
apply_operation(10, 5, multiply, "乘法");
}

fn apply_operation(a: i32, b: i32, op: fn(i32, i32) -> i32, name: &str) {
println!("{}: {} op {} = {}", name, a, b, op(a, b));
}

6.2 函数指针 vs 闭包

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
fn double(x: i32) -> i32 { x * 2 }

fn main() {
// 函数指针实现了所有三个闭包 trait: Fn, FnMut, FnOnce
// 所以函数指针可以在任何需要闭包的地方使用

let numbers = vec![1, 2, 3, 4, 5];

// 使用函数指针
let doubled: Vec<i32> = numbers.iter().map(|&x| double(x)).collect();
println!("函数指针: {:?}", doubled);

// 使用闭包
let tripled: Vec<i32> = numbers.iter().map(|&x| x * 3).collect();
println!("闭包: {:?}", tripled);

// 使用函数指针代替简单闭包
let strings = vec!["1", "2", "3", "4", "5"];
// parse::<i32> 是函数,可以直接传递
let parsed: Vec<i32> = strings.iter().map(|s| s.parse::<i32>().unwrap()).collect();
println!("解析: {:?}", parsed);

// 枚举变体也可以作为函数指针
let list_of_options: Vec<Option<i32>> = (0..5).map(Some).collect();
println!("Option 列表: {:?}", list_of_options);

// 元组结构体的构造函数也是函数指针
#[derive(Debug)]
struct Wrapper(i32);
let wrapped: Vec<Wrapper> = (0..5).map(Wrapper).collect();
println!("包装列表: {:?}", wrapped);
}

7. 高阶函数

高阶函数是接受函数作为参数或返回函数的函数。

7.1 函数作为参数

1
2
3
4
5
6
7
8
9
10
11
fn apply_twice(f: fn(i32) -> i32, x: i32) -> i32 {
f(f(x))
}

fn double(x: i32) -> i32 { x * 2 }
fn increment(x: i32) -> i32 { x + 1 }

fn main() {
println!("double 两次: {}", apply_twice(double, 5)); // 20
println!("increment 两次: {}", apply_twice(increment, 5)); // 7
}

7.2 使用泛型接受闭包

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
// 使用泛型约束接受闭包(更灵活,推荐方式)
fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 {
f(x)
}

// 接受闭包并多次调用
fn apply_n_times<F: Fn(i32) -> i32>(f: F, x: i32, n: u32) -> i32 {
let mut result = x;
for _ in 0..n {
result = f(result);
}
result
}

// 传递闭包给回调函数
fn process_data<F: Fn(&[i32]) -> i32>(data: &[i32], processor: F) -> i32 {
println!("处理 {} 个元素", data.len());
processor(data)
}

fn main() {
// 传入函数
fn square(x: i32) -> i32 { x * x }
println!("apply(square, 5) = {}", apply(square, 5));

// 传入闭包
println!("apply(|x| x + 10, 5) = {}", apply(|x| x + 10, 5));

// 多次应用
println!("apply_n_times(|x| x * 2, 1, 10) = {}",
apply_n_times(|x| x * 2, 1, 10)); // 1024

// 处理数据
let data = vec![1, 2, 3, 4, 5];

let sum = process_data(&data, |d| d.iter().sum());
println!("求和: {}", sum);

let max = process_data(&data, |d| *d.iter().max().unwrap());
println!("最大值: {}", max);

let product = process_data(&data, |d| d.iter().product());
println!("乘积: {}", product);
}

7.3 函数式编程风格

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
fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// ========== 链式调用 ==========
// 求 1-10 中偶数的平方和
let result: i32 = numbers.iter()
.filter(|&&x| x % 2 == 0) // 筛选偶数
.map(|&x| x * x) // 求平方
.sum(); // 求和
println!("偶数平方和: {}", result); // 220

// 求 1-10 中奇数的乘积
let product: i32 = numbers.iter()
.filter(|&&x| x % 2 != 0)
.copied()
.product();
println!("奇数乘积: {}", product); // 945

// ========== fold(折叠/归约) ==========
// fold 是最通用的归约操作
let sum = numbers.iter().fold(0, |acc, &x| acc + x);
println!("fold 求和: {}", sum);

// 使用 fold 拼接字符串
let text = numbers.iter()
.fold(String::new(), |acc, &x| {
if acc.is_empty() {
format!("{}", x)
} else {
format!("{}, {}", acc, x)
}
});
println!("fold 拼接: [{}]", text);

// ========== 组合高阶函数 ==========
let words = vec!["hello", "world", "foo", "bar", "rust", "programming"];

// 找出长度大于3的单词,转为大写
let result: Vec<String> = words.iter()
.filter(|w| w.len() > 3)
.map(|w| w.to_uppercase())
.collect();
println!("长单词大写: {:?}", result);

// 扁平化 + 映射(flat_map)
let sentences = vec!["hello world", "foo bar baz"];
let all_words: Vec<&str> = sentences.iter()
.flat_map(|s| s.split_whitespace())
.collect();
println!("所有单词: {:?}", all_words);

// ========== any / all / find ==========
let has_even = numbers.iter().any(|&x| x % 2 == 0);
println!("包含偶数: {}", has_even);

let all_positive = numbers.iter().all(|&x| x > 0);
println!("全部为正: {}", all_positive);

let first_gt_5 = numbers.iter().find(|&&x| x > 5);
println!("第一个>5: {:?}", first_gt_5);

let position = numbers.iter().position(|&x| x == 7);
println!("7 的位置: {:?}", position);
}

8. 闭包(Closure)

闭包是可以捕获其所在环境中变量的匿名函数。

8.1 闭包的定义语法

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
fn main() {
// ========== 闭包的多种写法 ==========

// 完整写法(带类型标注)
let add = |a: i32, b: i32| -> i32 { a + b };
println!("add(3, 4) = {}", add(3, 4));

// 省略类型标注(编译器自动推断)
let multiply = |a, b| a * b;
println!("multiply(3, 4) = {}", multiply(3, 4i32));

// 单表达式可以省略花括号
let double = |x| x * 2;
println!("double(5) = {}", double(5i32));

// 无参数闭包
let greet = || println!("Hello, Closure!");
greet();

// 多行闭包
let complex = |x: i32| {
let y = x * 2;
let z = y + 10;
z * z
};
println!("complex(3) = {}", complex(3));

// ========== 闭包类型推断 ==========
// 闭包的类型在第一次调用时确定
let closure = |x| x;

let s = closure(String::from("hello")); // 确定为 String -> String
println!("closure result: {}", s);

// 之后不能传入其他类型
// let n = closure(5); // 编译错误!已确定为 String -> String
}

8.2 闭包捕获环境变量

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
fn main() {
// ========== 捕获不可变引用 ==========
let name = String::from("Rust");
let greeting = || println!("Hello, {}!", name); // 捕获 name 的引用

greeting();
greeting();
println!("name 仍然有效: {}", name); // name 仍可使用

// ========== 捕获可变引用 ==========
let mut count = 0;
let mut increment = || {
count += 1; // 捕获 count 的可变引用
println!("count = {}", count);
};

increment(); // 1
increment(); // 2
increment(); // 3
// 注意:在 increment 存在期间,不能再借用 count
// println!("{}", count); // 如果取消这行注释并在 increment 之前使用,会编译错误

// increment 离开作用域后,count 可以再次使用
drop(increment);
println!("最终 count = {}", count);

// ========== 捕获多个变量 ==========
let x = 10;
let y = 20;
let sum = || x + y; // 同时捕获 x 和 y
println!("x + y = {}", sum());

// ========== 捕获与作用域 ==========
let data = vec![1, 2, 3];
let contains = |target: &i32| data.contains(target);

println!("包含 2: {}", contains(&2));
println!("包含 5: {}", contains(&5));
println!("data 仍然有效: {:?}", data);
}

8.3 三种闭包 trait

Rust 的闭包实现了以下三种 trait 之一或多个:

1
2
3
4
5
6
7
FnOnce: 获取所有权,只能调用一次

FnMut: 获取可变引用,可以多次调用

Fn: 获取不可变引用,可以多次调用

(Fn 是 FnMut 的子 trait,FnMut 是 FnOnce 的子 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
fn main() {
// ========== Fn:不可变借用环境 ==========
let name = String::from("Rust");

// 只读取 name,实现 Fn
let greet = || println!("Hello, {}!", name);

greet(); // 可以多次调用
greet();
println!("name 仍有效: {}", name);

// ========== FnMut:可变借用环境 ==========
let mut total = 0;

// 修改 total,实现 FnMut(也实现了 FnOnce)
let mut add_to_total = |x: i32| {
total += x;
};

add_to_total(10);
add_to_total(20);
add_to_total(30);

drop(add_to_total);
println!("total = {}", total); // 60

// ========== FnOnce:获取所有权 ==========
let data = vec![1, 2, 3];

// 消费 data(移出环境),只能实现 FnOnce
let consume = || {
let moved_data = data; // 获取 data 的所有权
println!("消费数据: {:?}", moved_data);
// moved_data 在这里被 drop
};

consume(); // 只能调用一次
// consume(); // 编译错误!FnOnce 只能调用一次
// println!("{:?}", data); // 编译错误!data 已被移动

// ========== 演示三种 trait 的约束 ==========
fn call_fn<F: Fn()>(f: F) {
f();
f(); // Fn 可以多次调用
}

fn call_fn_mut<F: FnMut()>(mut f: F) {
f();
f(); // FnMut 可以多次调用
}

fn call_fn_once<F: FnOnce()>(f: F) {
f(); // FnOnce 只调用一次
}

let s = String::from("hello");
let print_s = || println!("{}", s); // Fn 闭包

call_fn(print_s); // Fn 可以传给 Fn
// call_fn_mut(print_s); // Fn 也可以传给 FnMut
// call_fn_once(print_s); // Fn 也可以传给 FnOnce
}

8.4 move 关键字与闭包

move 强制闭包获取所有捕获变量的所有权。

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
use std::thread;

fn main() {
// ========== 基本 move 用法 ==========
let name = String::from("Rust");

// 不使用 move:闭包借用 name
let greet = || println!("Hello, {}!", name);
greet();
println!("name 仍有效: {}", name);

// 使用 move:闭包获取 name 的所有权
let name2 = String::from("World");
let greet2 = move || println!("Hello, {}!", name2);
greet2();
// println!("{}", name2); // 编译错误!name2 已被移动到闭包

// ========== move 在线程中的必要性 ==========
let data = vec![1, 2, 3];

// 线程可能比主线程活得更久,所以必须使用 move 转移所有权
let handle = thread::spawn(move || {
println!("线程中的数据: {:?}", data);
});

// println!("{:?}", data); // 编译错误!data 已移动到线程
handle.join().unwrap();

// ========== move 与 Copy 类型 ==========
let x = 42; // i32 实现了 Copy

let closure = move || println!("x = {}", x);
closure();

// x 仍然有效,因为 i32 是 Copy 的
// move 会复制 Copy 类型,而不是移动
println!("x 仍然有效: {}", x);

// ========== 在 move 前克隆 ==========
let shared_data = String::from("shared");
let cloned = shared_data.clone(); // 在 move 前克隆

let closure1 = move || println!("closure1: {}", cloned);
let closure2 = || println!("closure2: {}", shared_data);

closure1();
closure2();
println!("shared_data 仍有效: {}", shared_data);
}

8.5 闭包作为函数参数

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
// ========== 方式1:使用泛型约束(推荐,零成本抽象) ==========
fn apply_fn<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 {
f(x)
}

// 使用 where 子句(更清晰)
fn apply_fn_where<F>(f: F, x: i32) -> i32
where
F: Fn(i32) -> i32
{
f(x)
}

// ========== 方式2:使用 impl Trait(语法糖,本质同泛型) ==========
fn apply_impl(f: impl Fn(i32) -> i32, x: i32) -> i32 {
f(x)
}

// ========== 方式3:使用 dyn Trait(动态分发,有运行时开销) ==========
fn apply_dyn(f: &dyn Fn(i32) -> i32, x: i32) -> i32 {
f(x)
}

// Box<dyn Fn> 用于存储闭包
fn apply_box(f: Box<dyn Fn(i32) -> i32>, x: i32) -> i32 {
f(x)
}

fn main() {
let double = |x| x * 2;
let add_ten = |x| x + 10;

// 泛型方式
println!("泛型: {}", apply_fn(double, 5));
println!("where: {}", apply_fn_where(add_ten, 5));

// impl Trait 方式
println!("impl: {}", apply_impl(double, 5));

// dyn Trait 方式
println!("dyn: {}", apply_dyn(&double, 5));

// Box<dyn Fn> 方式
println!("box: {}", apply_box(Box::new(double), 5));

// 在集合中存储不同的闭包(需要 dyn)
let operations: Vec<Box<dyn Fn(i32) -> i32>> = vec![
Box::new(|x| x + 1),
Box::new(|x| x * 2),
Box::new(|x| x * x),
];

let x = 5;
for (i, op) in operations.iter().enumerate() {
println!("operations[{}]({}) = {}", i, x, op(x));
}
}

8.6 闭包作为返回值

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
// 使用 impl Fn 返回闭包(推荐,编译时确定类型)
fn make_adder(n: i32) -> impl Fn(i32) -> i32 {
move |x| x + n // 必须使用 move,因为 n 是函数局部变量
}

fn make_multiplier(factor: i32) -> impl Fn(i32) -> i32 {
move |x| x * factor
}

// 返回不同闭包时需要使用 Box<dyn Fn>
fn make_operation(op: &str) -> Box<dyn Fn(i32, i32) -> i32> {
match op {
"add" => Box::new(|a, b| a + b),
"sub" => Box::new(|a, b| a - b),
"mul" => Box::new(|a, b| a * b),
"div" => Box::new(|a, b| a / b),
_ => Box::new(|_, _| 0),
}
}

// 返回组合函数
fn compose<F, G>(f: F, g: G) -> impl Fn(i32) -> i32
where
F: Fn(i32) -> i32,
G: Fn(i32) -> i32,
{
move |x| f(g(x))
}

fn main() {
// 使用工厂函数
let add5 = make_adder(5);
let times3 = make_multiplier(3);

println!("add5(10) = {}", add5(10)); // 15
println!("times3(10) = {}", times3(10)); // 30

// 动态选择操作
let operations = vec!["add", "sub", "mul", "div"];
for op in &operations {
let f = make_operation(op);
println!("{}(10, 3) = {}", op, f(10, 3));
}

// 函数组合
let add5_then_times3 = compose(times3, add5);
println!("(5 + 5) * 3 = {}", add5_then_times3(5)); // 30

let times3_then_add5 = compose(add5, times3);
println!("5 * 3 + 5 = {}", times3_then_add5(5)); // 20
}

8.7 闭包的实际应用

排序

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
fn main() {
// ========== 自定义排序 ==========
let mut numbers = vec![3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5];

// 升序排序
numbers.sort_by(|a, b| a.cmp(b));
println!("升序: {:?}", numbers);

// 降序排序
numbers.sort_by(|a, b| b.cmp(a));
println!("降序: {:?}", numbers);

// 按绝对值排序
let mut nums = vec![-5, 3, -1, 4, -2];
nums.sort_by_key(|x| x.abs());
println!("按绝对值: {:?}", nums);

// 结构体排序
#[derive(Debug)]
struct Student {
name: String,
score: f64,
}

let mut students = vec![
Student { name: "Alice".into(), score: 92.5 },
Student { name: "Bob".into(), score: 87.0 },
Student { name: "Charlie".into(), score: 95.0 },
Student { name: "Diana".into(), score: 87.0 },
];

// 按分数降序排列,分数相同按姓名升序
students.sort_by(|a, b| {
b.score.partial_cmp(&a.score)
.unwrap()
.then(a.name.cmp(&b.name))
});

println!("排名:");
for (i, s) in students.iter().enumerate() {
println!(" {}. {} ({:.1})", i + 1, s.name, s.score);
}
}

过滤与映射

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
fn main() {
let words = vec![
"apple", "banana", "cherry", "date", "elderberry",
"fig", "grape", "honeydew",
];

// 过滤:长度大于 5 的单词
let long_words: Vec<&&str> = words.iter()
.filter(|w| w.len() > 5)
.collect();
println!("长单词: {:?}", long_words);

// 映射:转为大写
let upper: Vec<String> = words.iter()
.map(|w| w.to_uppercase())
.collect();
println!("大写: {:?}", upper);

// filter_map:过滤并映射(同时进行)
let numbers = vec!["1", "abc", "3", "def", "5", "6"];
let valid_numbers: Vec<i32> = numbers.iter()
.filter_map(|s| s.parse::<i32>().ok())
.collect();
println!("有效数字: {:?}", valid_numbers);

// 链式操作
let result: Vec<String> = words.iter()
.filter(|w| w.starts_with('a') || w.starts_with('b'))
.map(|w| format!("{}({})", w, w.len()))
.collect();
println!("a/b 开头: {:?}", result);

// 使用 for_each 替代 for 循环
println!("\nfor_each:");
words.iter()
.enumerate()
.for_each(|(i, w)| println!(" [{}] {}", i, w));
}

迭代器与闭包组合

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
fn main() {
// ========== reduce / fold ==========
let numbers = vec![1, 2, 3, 4, 5];

// fold:带初始值的归约
let sum = numbers.iter().fold(0, |acc, &x| acc + x);
println!("fold 求和: {}", sum);

let factorial = (1..=10).fold(1u64, |acc, x| acc * x);
println!("10! = {}", factorial);

// reduce:无初始值的归约
let max = numbers.iter().copied().reduce(|a, b| if a > b { a } else { b });
println!("reduce 最大值: {:?}", max);

// ========== scan:有状态的映射 ==========
let running_sum: Vec<i32> = numbers.iter()
.scan(0, |state, &x| {
*state += x;
Some(*state)
})
.collect();
println!("累积和: {:?}", running_sum); // [1, 3, 6, 10, 15]

// ========== 分组和分区 ==========
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// partition:分为两组
let (evens, odds): (Vec<i32>, Vec<i32>) = numbers.iter()
.partition(|&&x| x % 2 == 0);
println!("偶数: {:?}", evens);
println!("奇数: {:?}", odds);

// ========== take_while / skip_while ==========
let data = vec![2, 4, 6, 1, 3, 5, 8, 10];

let prefix: Vec<&i32> = data.iter().take_while(|&&x| x % 2 == 0).collect();
println!("take_while 偶数前缀: {:?}", prefix); // [2, 4, 6]

let suffix: Vec<&i32> = data.iter().skip_while(|&&x| x % 2 == 0).collect();
println!("skip_while 跳过偶数: {:?}", suffix); // [1, 3, 5, 8, 10]

// ========== 实际应用:单词频率统计 ==========
let text = "the quick brown fox jumps over the lazy dog the fox";
let mut word_count = std::collections::HashMap::new();

text.split_whitespace()
.for_each(|word| {
*word_count.entry(word).or_insert(0) += 1;
});

println!("\n单词频率:");
let mut counts: Vec<_> = word_count.iter().collect();
counts.sort_by(|a, b| b.1.cmp(a.1));
for (word, count) in counts {
println!(" {}: {}", word, count);
}
}

回调与事件处理

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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// 使用闭包实现简单的事件系统
struct EventEmitter {
listeners: Vec<Box<dyn Fn(&str)>>,
}

impl EventEmitter {
fn new() -> Self {
EventEmitter {
listeners: Vec::new(),
}
}

fn on<F: Fn(&str) + 'static>(&mut self, listener: F) {
self.listeners.push(Box::new(listener));
}

fn emit(&self, event: &str) {
for listener in &self.listeners {
listener(event);
}
}
}

// 使用闭包实现策略模式
struct Validator {
rules: Vec<Box<dyn Fn(&str) -> Result<(), String>>>,
}

impl Validator {
fn new() -> Self {
Validator { rules: Vec::new() }
}

fn add_rule<F: Fn(&str) -> Result<(), String> + 'static>(&mut self, rule: F) {
self.rules.push(Box::new(rule));
}

fn validate(&self, input: &str) -> Result<(), Vec<String>> {
let errors: Vec<String> = self.rules.iter()
.filter_map(|rule| rule(input).err())
.collect();

if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
}

fn main() {
// 事件系统
let mut emitter = EventEmitter::new();

emitter.on(|event| println!("监听器1: 收到事件 '{}'", event));
emitter.on(|event| println!("监听器2: 处理事件 '{}'", event));
emitter.on(|event| {
if event == "error" {
println!("监听器3: 发现错误事件!");
}
});

println!("=== 触发 'click' 事件 ===");
emitter.emit("click");

println!("\n=== 触发 'error' 事件 ===");
emitter.emit("error");

// 验证器
println!("\n=== 输入验证 ===");
let mut validator = Validator::new();

validator.add_rule(|input| {
if input.len() >= 3 {
Ok(())
} else {
Err("长度必须至少3个字符".to_string())
}
});

validator.add_rule(|input| {
if input.chars().any(|c| c.is_uppercase()) {
Ok(())
} else {
Err("必须包含大写字母".to_string())
}
});

validator.add_rule(|input| {
if input.chars().any(|c| c.is_numeric()) {
Ok(())
} else {
Err("必须包含数字".to_string())
}
});

let test_inputs = ["Ab1", "ab", "ABC", "Hello123"];

for input in &test_inputs {
match validator.validate(input) {
Ok(()) => println!("'{}' -> 验证通过", input),
Err(errors) => {
println!("'{}' -> 验证失败:", input);
for err in errors {
println!(" - {}", err);
}
}
}
}
}

总结

本章我们深入学习了 Rust 的函数与闭包:

  1. 函数定义:使用 fn 关键字,snake_case 命名,参数和返回值必须标注类型
  2. 表达式返回:函数体最后一个无分号的表达式自动成为返回值
  3. 多返回值:使用元组或自定义结构体返回多个值
  4. 发散函数:使用 ! 返回类型表示永远不返回的函数
  5. 函数指针fn 类型允许将函数作为值传递
  6. 高阶函数:函数可以接受函数/闭包作为参数
  7. 闭包
    • 语法:|参数| 表达式
    • 捕获环境变量(不可变引用、可变引用、所有权)
    • 三种 trait:FnFnMutFnOnce
    • move 关键字强制转移所有权
    • 作为参数:泛型约束 / impl Fn / dyn Fn
    • 作为返回值:impl Fn / Box<dyn Fn>
    • 实际应用:排序、过滤、映射、事件处理等

闭包是 Rust 函数式编程的核心,与迭代器结合使用可以写出简洁高效的代码。