组合器的作用
一般函数都是返回 Option 或 Result。但是每次都要判断它们是否是 None 或 Err, 再取出 Value 来操作会导致很烦琐, 有些情况下, 用组合器会比较方便。比如: 使用组合器可以链式编程。比如, 处理容器数据:
1
2
3
4
5
6
7
| let results = vec![1, 2, 3, 4]
.into_iter()
.filter(|x| x % 2 == 0) // 保留偶数
.map(|x| x * 3) // 放大三倍
.collect::<Vec<_>>(); // 重新收集
assert_eq!(results, vec![6, 12]);
|
if let
, match
和组合器使用的理解:
至于说能解决过深的嵌套, 我倒觉得没有解决。有些情况下, 将 if let
或 match
的写法改为组合器, 我觉得会增加阅读代码的难度。
我觉得是有 if let
, match
和组合器的用法, 我觉得和 C 语言的 for
和 while
的类似, 主要是思路的表达。比如: 消费者消费直到 count == 0
用 while 会更加表示出思路, 而不是用 for。
if let else
的情况用 match
会比较清晰:
1
2
3
4
5
6
7
8
9
| if let Some(v) = value {
} else {
}
// 改为 match 会比较好
match value {
Some(v) => {},
None=> {}
}
|
Option 的常用组合器
1. 值转换组合器
map
- 转换 Some
值
1
2
3
4
5
6
7
| fn double(x: i32) -> i32 { x * 2 }
let some: Option<i32> = Some(2);
let doubled = some.map(double); // Some(4)
let none: Option<i32> = None;
let still_none = none.map(double); // None
|
map_or
- 转换或提供默认值
1
2
3
4
5
| let some: Option<i32> = Some(2);
let value = some.map_or(0, |x| x * 3); // 6
let none: Option<i32> = None;
let default = none.map_or(0, |x| x * 3); // 0
|
map_or_else
- 转换或通过闭包计算默认值
1
2
3
4
5
| let some: Option<i32> = Some(2);
let value = some.map_or_else(|| 0, |x| x * 3); // 6
let none: Option<i32> = None;
let default = none.map_or_else(|| 0, |x| x * 3); // 0
|
理解与记忆:
- 问: 为什么 map 返回 Option, 而
map_or/map_or_else
返回 Value。 - 答: 因为它们提供了默认值, 所以没有必要 Option, 返回 Value 即可。
2. 链式操作组合器
and_then
- 链式操作(类似 flatMap)
1
2
3
4
5
6
7
| fn reciprocal(x: f64) -> Option<f64> {
if x != 0.0 { Some(1.0 / x) } else { None }
}
Some(2.0).and_then(reciprocal); // Some(0.5)
Some(0.0).and_then(reciprocal); // None
None.and_then(reciprocal); // None
|
or_else
- 处理 None
情况
1
2
3
4
| fn fallback() -> Option<i32> { Some(0) }
Some(2).or_else(fallback); // Some(2)
None.or_else(fallback); // Some(0)
|
3. 解包组合器
unwrap
- 解包 Some
值或 panic
1
2
| Some(2).unwrap(); // 2
// None.unwrap(); // panic!
|
unwrap_or
- 解包或提供默认值
1
2
| Some(2).unwrap_or(0); // 2
None.unwrap_or(0); // 0
|
unwrap_or_else
- 解包或通过闭包计算默认值
1
2
| Some(2).unwrap_or_else(|| 0); // 2
None.unwrap_or_else(|| 0); // 0
|
expect
- 解包 Some
值或 panic 并显示消息
1
2
| Some(2).expect("should be number"); // 2
// None.expect("should be number"); // panic with message
|
4. 过滤和条件组合器
filter
- 条件过滤
1
2
3
| Some(3).filter(|&x| x > 1); // Some(3)
Some(0).filter(|&x| x > 1); // None
None.filter(|&x| x > 1); // None
|
take
- 取出值并留下 None
1
2
3
| let mut x = Some(2);
let taken = x.take(); // Some(2)
assert_eq!(x, None); // x 现在是 None
|
replace
- 替换值并返回旧值
1
2
3
| let mut x = Some(2);
let old = x.replace(5); // Some(2)
assert_eq!(x, Some(5)); // x 现在是 Some(5)
|
5. 布尔判断组合器
is_some
/ is_none
- 检查 Option 状态
1
2
| Some(2).is_some(); // true
None.is_none(); // true
|
contains
- 检查包含特定值
1
2
3
| Some(2).contains(&2); // true
Some(3).contains(&2); // false
None.contains(&2); // false
|
6. 组合多个 Option
and
/ or
- 逻辑组合
1
2
3
4
| Some(2).and(Some(3)); // Some(3)
Some(2).and(None); // None
None.or(Some(3)); // Some(3)
None.or(None); // None
|
xor
- 排他性 OR
1
2
3
4
| Some(2).xor(None); // Some(2)
None.xor(Some(3)); // Some(3)
Some(2).xor(Some(3)); // None
None.xor(None); // None
|
7. 转换组合器
ok_or
- 转换为 Result
1
2
| Some(2).ok_or("error"); // Ok(2)
None.ok_or("error"); // Err("error")
|
ok_or_else
- 转换为 Result 并提供错误闭包
1
| None.ok_or_else(|| "error".to_string()); // Err("error".to_string())
|
transpose
- 转换嵌套的 Option 和 Result
1
2
| let x: Option<Result<i32, &str>> = Some(Ok(5));
let y: Result<Option<i32>, &str> = x.transpose(); // Ok(Some(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
| struct User {
name: String,
age: Option<u32>,
email: Option<String>,
}
fn get_user_email(user: &User) -> Option<String> {
user.email.clone()
}
fn get_user_age(user: &User) -> Option<u32> {
user.age
}
fn process_user(user: &User) -> Option<String> {
get_user_age(user)
.filter(|&age| age >= 18)
.and_then(|_| get_user_email(user))
.map(|email| email.to_uppercase())
}
let adult_user = User {
name: "Alice".to_string(),
age: Some(25),
email: Some("alice@example.com".to_string()),
};
let child_user = User {
name: "Bob".to_string(),
age: Some(12),
email: Some("bob@example.com".to_string()),
};
assert_eq!(process_user(&adult_user), Some("ALICE@EXAMPLE.COM".to_string()));
assert_eq!(process_user(&child_user), None);
|
Result 的常用组合器
1. 值转换组合器
map
- 转换成功值
1
2
3
4
5
6
7
| fn double(x: i32) -> i32 { x * 2 }
let res: Result<i32, &str> = Ok(2);
let doubled = res.map(double); // Ok(4)
let err: Result<i32, &str> = Err("error");
let still_err = err.map(double); // Err("error")
|
map_err
- 转换错误值
1
2
3
4
| fn stringify(x: &str) -> String { x.to_string() }
let res: Result<i32, &str> = Err("error");
let mapped_err = res.map_err(stringify); // Err("error".to_string())
|
map_or
- 转换或提供默认值
1
2
3
4
5
| let res: Result<i32, &str> = Ok(2);
let value = res.map_or(0, |x| x * 3); // 6
let err: Result<i32, &str> = Err("error");
let default = err.map_or(0, |x| x * 3); // 0
|
map_or_else
- 转换或通过闭包计算默认值
1
2
3
4
5
| let res: Result<i32, &str> = Ok(2);
let value = res.map_or_else(|_| 0, |x| x * 3); // 6
let err: Result<i32, &str> = Err("error");
let default = err.map_or_else(|e| e.len() as i32, |x| x * 3); // 5
|
2. 链式操作组合器
and_then
- 链式操作(类似 flatMap)
1
2
3
4
5
6
7
| fn sqrt(x: f64) -> Result<f64, String> {
if x >= 0.0 { Ok(x.sqrt()) } else { Err("negative number".to_string()) }
}
Ok(4.0).and_then(sqrt); // Ok(2.0)
Ok(-1.0).and_then(sqrt); // Err("negative number")
Err("already error").and_then(sqrt); // Err("already error")
|
or_else
- 处理错误情况
1
2
3
4
5
6
7
| fn recover(e: &str) -> Result<i32, String> {
if e == "retry" { Ok(0) } else { Err(e.to_string()) }
}
Err("retry").or_else(recover); // Ok(0)
Err("fatal").or_else(recover); // Err("fatal")
Ok(2).or_else(recover); // Ok(2)
|
3. 解包组合器
unwrap
- 解包成功值或 panic
1
2
| Ok(2).unwrap(); // 2
// Err("error").unwrap(); // panic!
|
unwrap_or
- 解包或提供默认值
1
2
| Ok(2).unwrap_or(0); // 2
Err("error").unwrap_or(0); // 0
|
unwrap_or_else
- 解包或通过闭包计算默认值
1
2
| Ok(2).unwrap_or_else(|e| e.len() as i32); // 2
Err("error").unwrap_or_else(|e| e.len() as i32); // 5
|
expect
- 解包成功值或 panic 并显示消息
1
2
| Ok(2).expect("should be number"); // 2
// Err("error").expect("should be number"); // panic with message
|
4. 布尔判断组合器
is_ok
/ is_err
- 检查结果状态
1
2
| Ok(2).is_ok(); // true
Err("error").is_err(); // true
|
contains
/ contains_err
- 检查包含特定值
1
2
| Ok(2).contains(&2); // true
Err("error").contains_err(&"error"); // true
|
5. 高级组合器
and
/ or
- 组合多个 Result
1
2
3
4
| Ok(2).and(Ok(3)); // Ok(3)
Ok(2).and(Err("error")); // Err("error")
Err("error1").or(Ok(3)); // Ok(3)
Err("error1").or(Err("error2")); // Err("error2")
|
transpose
- 转换嵌套的 Result 和 Option
1
2
| let x: Result<Option<i32>, &str> = Ok(Some(5));
let y: Option<Result<i32, &str>> = x.transpose(); // Some(Ok(5))
|
实际应用示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| use std::fs::File;
use std::io::Read;
fn read_file(path: &str) -> Result<String, std::io::Error> {
File::open(path)
.and_then(|mut file| {
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
})
}
fn process_file(path: &str) -> Result<usize, String> {
read_file(path)
.map_err(|e| format!("Failed to read file: {}", e))
.and_then(|contents| {
if contents.is_empty() {
Err("Empty file".to_string())
} else {
Ok(contents.lines().count())
}
})
}
|