Rust 常用组合器

目录

组合器的作用

一般函数都是返回 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 letmatch 的写法改为组合器, 我觉得会增加阅读代码的难度。

  • 我觉得是有 if let, match 和组合器的用法, 我觉得和 C 语言的 forwhile 的类似, 主要是思路的表达。比如: 消费者消费直到 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())
            }
        })
}
0%