Rust 组合器汇总

2021-12-06 22:12:16 浏览数 (1)

1 Option 和 Result

Option<T> 用来表示有无,当有值时,为 Some(T);否则,为 None。

代码语言:txt复制
enum Option<T> {
    None,
    Some(T),
}

Result<T, E> 用来表示是否发生错误,当没有发生错误时,为 Ok(T);否则,为 Err(E)。

代码语言:txt复制
enum Result<T, E> {
    Ok(T),
    Err(E),
}

可以用 match 来匹配 Option 和 Result,也可以用下面提到的组合器简化代码。

2 处理 Option

2.1 None 时发生 panic

2.1.1 expect

  • 有值,返回值;否则,中断程序,打印 msg 错误信息。
  • 源码
代码语言:txt复制
pub fn expect(self, msg: &str) -> T {
    match self {
        Some(val) => val,
        None => expect_failed(msg),
    }
}
  • 例子
代码语言:txt复制
let x = Some("value");
assert_eq!(x.expect("the world is ending"), "value");

let x: Option<&str> = None;
x.expect("the world is ending"); // panics with `the world is ending`

2.1.2 unwrap

  • 有值,返回值;否则,中断程序。
  • 源码
代码语言:txt复制
pub fn unwrap(self) -> T {
    match self {
        Some(val) => val,
        None => panic!("called `Option::unwrap()` on a `None` value"),
    }
}
  • 例子
代码语言:txt复制
let x = Some("air");
assert_eq!(x.unwrap(), "air");

let x: Option<&str> = None;
assert_eq!(x.unwrap(), "air"); // fails

2.2 返回另外一个值

2.2.1 unwrap_or

  • 有值,返回值;否则返回一个默认值。
  • 源码
代码语言:txt复制
pub fn unwrap_or(self, def: T) -> T {
    match self {
        Some(x) => x,
        None => def,
    }
}
  • 例子
代码语言:txt复制
assert_eq!(Some("car").unwrap_or("bike"), "car");
assert_eq!(None.unwrap_or("bike"), "bike");
assert_eq!(None.unwrap_or(2), 2);

2.2.2 unwrap_or_else

  • 有值,返回值;否则,执行闭包。
  • 源码
代码语言:txt复制
pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
    match self {
        Some(x) => x,
        None => f(),
    }
}
  • 例子
代码语言:txt复制
let k = 10;
assert_eq!(Some(4).unwrap_or_else(|| 2 * k), 4);
assert_eq!(None.unwrap_or_else(|| 2 * k), 20);
assert_eq!(None.unwrap_or_else(|| "hello"), "hello");

2.2.3 map_or

  • 有值,则执行闭包返回值;否则,返回一个自定义的默认值。
  • 源码
代码语言:txt复制
pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
    match self {
        Some(t) => f(t),
        None => default,
    }
}
  • 例子
代码语言:txt复制
let x = Some("foo");
assert_eq!(x.map_or(42, |v| v.len()), 3);

let x: Option<&str> = None;
assert_eq!(x.map_or(42, |v| v.len()), 42);

2.2.4 map_or_else

  • 有值,执行闭包;否则执行另一个闭包。
  • 源码
代码语言:txt复制
pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
    match self {
        Some(t) => f(t),
        None => default(),
    }
}
  • 例子
代码语言:txt复制
let k = 21;

let x = Some("foo");
assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3);

let x: Option<&str> = None;
assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);

2.3 返回 Option

2.3.1 map

  • 改变值,并返回另一个 Option。
  • 源码
代码语言:txt复制
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
    match self {
        Some(x) => Some(f(x)),
        None => None,
    }
}
  • 例子
代码语言:txt复制
let maybe_some_string = Some(String::from("Hello, World!"));
// `Option::map` takes self *by value*, consuming `maybe_some_string`
let maybe_some_len = maybe_some_string.map(|s| s.len());

assert_eq!(maybe_some_len, Some(13));

2.3.2 and

  • 有值,返回另一 Option;否则返回 None。
  • 源码
代码语言:txt复制
pub fn and<U>(self, optb: Option<U>) -> Option<U> {
    match self {
        Some(_) => optb,
        None => None,
    }
}
  • 例子
代码语言:txt复制
let x = Some(2);
let y: Option<&str> = None;
assert_eq!(x.and(y), None);

let x: Option<u32> = None;
let y = Some("foo");
assert_eq!(x.and(y), None);

let x = Some(2);
let y = Some("foo");
assert_eq!(x.and(y), Some("foo"));

let x: Option<u32> = None;
let y: Option<&str> = None;
assert_eq!(x.and(y), None);

2.3.3 and_then

  • 有值,执行闭包;否则返回 None。
  • 源码
代码语言:txt复制
pub fn and_then<U, F: FnOnce(T) -> Option<U>>(self, f: F) -> Option<U> {
    match self {
        Some(x) => f(x),
        None => None,
    }
}
  • 例子
代码语言:txt复制
fn sq(x: u32) -> Option<u32> { Some(x * x) }
fn nope(_: u32) -> Option<u32> { None }

assert_eq!(Some(2).and_then(sq).and_then(sq), Some(16));
assert_eq!(Some(2).and_then(sq).and_then(nope), None);
assert_eq!(Some(2).and_then(nope).and_then(sq), None);
assert_eq!(None.and_then(sq).and_then(sq), None);

2.3.4 or

  • 有值,返回自身;否则返回自定义的 Option。
  • 源码
代码语言:txt复制
pub fn or(self, optb: Option<T>) -> Option<T> {
    match self {
        Some(_) => self,
        None => optb,
    }
}
  • 例子
代码语言:txt复制
let x = Some(2);
let y = None;
assert_eq!(x.or(y), Some(2));

let x = None;
let y = Some(100);
assert_eq!(x.or(y), Some(100));

let x = Some(2);
let y = Some(100);
assert_eq!(x.or(y), Some(2));

let x: Option<u32> = None;
let y = None;
assert_eq!(x.or(y), None);

2.3.5 or_else

  • 有值,返回自身;否则执行闭包。
  • 源码
代码语言:txt复制
pub fn or_else<F: FnOnce() -> Option<T>>(self, f: F) -> Option<T> {
    match self {
        Some(_) => self,
        None => f(),
    }
}
  • 例子
代码语言:txt复制
fn nobody() -> Option<&'static str> { None }
fn vikings() -> Option<&'static str> { Some("vikings") }

assert_eq!(Some("barbarians").or_else(vikings), Some("barbarians"));
assert_eq!(None.or_else(vikings), Some("vikings"));
assert_eq!(None.or_else(nobody), None);

2.3.6 take

  • 取出一个值。
  • 源码
代码语言:txt复制
pub fn take(&mut self) -> Option<T> {
    mem::replace(self, None)
}
  • 例子
代码语言:txt复制
let mut x = Some(2);
let y = x.take();
assert_eq!(x, None);
assert_eq!(y, Some(2));

let mut x: Option<u32> = None;
let y = x.take();
assert_eq!(x, None);
assert_eq!(y, None);

2.4 返回 Result

2.4.1 ok_or

  • 有值,返回 Result;否则返回自定义的错误。
  • 源码
代码语言:txt复制
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
    match self {
        Some(v) => Ok(v),
        None => Err(err),
    }
}
  • 例子
代码语言:txt复制
let x = Some("foo");
assert_eq!(x.ok_or(0), Ok("foo"));

let x: Option<&str> = None;
assert_eq!(x.ok_or(0), Err(0));

2.4.2 ok_or_else

  • 有值,返回 Result;否则执行代表错误的闭包。
  • 源码
代码语言:txt复制
pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
    match self {
        Some(v) => Ok(v),
        None => Err(err()),
    }
}
  • 例子
代码语言:txt复制
let x = Some("foo");
assert_eq!(x.ok_or_else(|| 0), Ok("foo"));

let x: Option<&str> = None;
assert_eq!(x.ok_or_else(|| 0), Err(0));

3 处理 Result

3.1 错误时发生 panic

3.1.1 expect

  • 正确,返回值;否则,中断程序,打印 msg 错误信息。
  • 源码
代码语言:txt复制
pub fn expect(self, msg: &str) -> T {
    match self {
        Ok(t) => t,
        Err(e) => unwrap_failed(msg, &e),
    }
}
  • 例子
代码语言:txt复制
let ok: Result<&'static str, anyhow::Error> = Ok("value");
assert_eq!(ok.expect("the world is ending"), "value");

let err: Result<&'static str, anyhow::Error> = Err(anyhow::anyhow!("error"));
err.expect("the world is ending"); // panics with `the world is ending`

3.1.2 unwrap

  • 正确,返回值;否则,中断程序。
  • 源码
代码语言:txt复制
pub fn unwrap(self) -> T {
    match self {
        Ok(t) => t,
        Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e),
    }
}
  • 例子
代码语言:txt复制
let ok: Result<&'static str, anyhow::Error> = Ok("value");
assert_eq!(ok.unwrap(), "value");

let err: Result<&'static str, anyhow::Error> = Err(anyhow::anyhow!("error"));
err.unwrap(); // fails

3.2 返回另外一个值

3.2.1 unwrap_or_default

  • 正确,返回值;否则,返回默认值。
  • 源码
代码语言:txt复制
pub fn unwrap_or_default(self) -> T {
    match self {
        Ok(x) => x,
        Err(_) => Default::default(),
    }
}
  • 例子
代码语言:txt复制
let good_year_from_input = "1909";
let good_year = good_year_from_input.parse().unwrap_or_default();
assert_eq!(1909, good_year);

let bad_year_from_input = "190blarg";
let bad_year = bad_year_from_input.parse().unwrap_or_default();
assert_eq!(0, bad_year);

3.2.2 unwrap_or

  • 正确,返回值;否则返回自定义默认值。
  • 源码
代码语言:txt复制
pub fn unwrap_or(self, default: T) -> T {
    match self {
        Ok(t) => t,
        Err(_) => default,
    }
}
  • 例子
代码语言:txt复制
let ok: Result<&'static str, anyhow::Error> = Ok("value");
assert_eq!(ok.unwrap_or("other"), "value");

let err: Result<&'static str, anyhow::Error> = Err(anyhow::anyhow!("error"));
assert_eq!(err.unwrap_or("other"), "other");

3.2.3 unwrap_or_else

  • 正确,返回值;否则,执行闭包。
  • 源码
代码语言:txt复制
pub fn unwrap_or_else<F: FnOnce(E) -> T>(self, op: F) -> T {
    match self {
        Ok(t) => t,
        Err(e) => op(e),
    }
}
  • 例子
代码语言:txt复制
let ok: Result<&'static str, anyhow::Error> = Ok("value");
assert_eq!(ok.unwrap_or_else(|v| "other"), "value");

let err: Result<&'static str, anyhow::Error> = Err(anyhow::anyhow!("error"));
assert_eq!(err.unwrap_or_else(|v| "other"), "other");

3.2.4 map_or

  • 正确,则执行闭包返回值;否则,返回一个自定义的默认值。
  • 源码
代码语言:txt复制
pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
    match self {
        Ok(t) => f(t),
        Err(_) => default,
    }
}
  • 例子
代码语言:txt复制
let ok: Result<&'static str, anyhow::Error> = Ok("value");
assert_eq!(ok.map_or(42, |v| v.len()), 5);

let err: Result<&'static str, anyhow::Error> = Err(anyhow::anyhow!("error"));
assert_eq!(err.map_or(42, |v| v.len()), 42);

3.2.5 map_or_else

  • 正确,则执行第 2 个闭包;否则执行第 1 个闭包。
  • 源码
代码语言:txt复制
pub fn map_or_else<U, D: FnOnce(E) -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
    match self {
        Ok(t) => f(t),
        Err(e) => default(e),
    }
}
  • 例子
代码语言:txt复制
let k = 21;

let ok: Result<&'static str, anyhow::Error> = Ok("value");
assert_eq!(ok.map_or_else(|v| 2 * k, |v| v.len()), 5);

let err: Result<&'static str, anyhow::Error> = Err(anyhow::anyhow!("error"));
assert_eq!(err.map_or_else(|v| 2 * k, |v| v.len()), 42);

3.3 返回 Result

3.3.1 map

  • 正确,则改变值,并返回另一个 Result。
  • 源码
代码语言:txt复制
pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Result<U, E> {
    match self {
        Ok(t) => Ok(op(t)),
        Err(e) => Err(e),
    }
}
  • 例子
代码语言:txt复制
let ok: Result<&'static str, anyhow::Error> = Ok("value");
assert_eq!(ok.map(|s| s.len()).unwrap(), 5);

3.3.2 map_err

  • 错误,则对错误执行闭包,并返回另一个 Result。
  • 源码
代码语言:txt复制
pub fn map_err<F, O: FnOnce(E) -> F>(self, op: O) -> Result<T, F> {
    match self {
        Ok(t) => Ok(t),
        Err(e) => Err(op(e)),
    }
}
  • 例子
代码语言:txt复制
fn stringify(x: u32) -> String { format!("error code: {}", x) }

let x: Result<u32, u32> = Ok(2);
assert_eq!(x.map_err(stringify), Ok(2));

let x: Result<u32, u32> = Err(13);
assert_eq!(x.map_err(stringify), Err("error code: 13".to_string()));

3.3.2 and

  • 正确,则返回另一 Result。
  • 源码
代码语言:txt复制
pub fn and<U>(self, res: Result<U, E>) -> Result<U, E> {
    match self {
        Ok(_) => res,
        Err(e) => Err(e),
    }
}
  • 例子
代码语言:txt复制
let ok: Result<u32, &str> = Ok(2);
let x1: Result<u32, &str> = Ok(3);
assert_eq!(ok.and(x1), Ok(3));

let err: Result<u32, &str> = Err("error 1");
let x2: Result<u32, &str> = Err("early 2");
assert_eq!(err.and(x2), Err("error 1"));

3.3.3 and_then

  • 正确,则执行闭包。
  • 源码
代码语言:txt复制
pub fn and_then<U, F: FnOnce(T) -> Result<U, E>>(self, op: F) -> Result<U, E> {
    match self {
        Ok(t) => op(t),
        Err(e) => Err(e),
    }
}
  • 例子
代码语言:txt复制
fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }
fn err(x: u32) -> Result<u32, u32> { Err(x) }

assert_eq!(Ok(2).and_then(sq).and_then(sq), Ok(16));
assert_eq!(Ok(2).and_then(sq).and_then(err), Err(4));
assert_eq!(Ok(2).and_then(err).and_then(sq), Err(2));
assert_eq!(Err(3).and_then(sq).and_then(sq), Err(3));

3.3.4 or

  • 错误,则返回另一个 Result。
  • 源码
代码语言:txt复制
pub fn or<F>(self, res: Result<T, F>) -> Result<T, F> {
    match self {
        Ok(v) => Ok(v),
        Err(_) => res,
    }
}
  • 例子
代码语言:txt复制
let x: Result<u32, &str> = Ok(2);
let y: Result<u32, &str> = Err("late error");
assert_eq!(x.or(y), Ok(2));

let x: Result<u32, &str> = Err("not a 2");
let y: Result<u32, &str> = Err("late error");
assert_eq!(x.or(y), Err("late error"));

3.3.5 or_else

  • 错误,则执行闭包。
  • 源码
代码语言:txt复制
pub fn or_else<F, O: FnOnce(E) -> Result<T, F>>(self, op: O) -> Result<T, F> {
    match self {
        Ok(t) => Ok(t),
        Err(e) => op(e),
    }
}
  • 例子
代码语言:txt复制
fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }
fn err(x: u32) -> Result<u32, u32> { Err(x) }

assert_eq!(Ok(2).or_else(sq).or_else(sq), Ok(2));
assert_eq!(Ok(2).or_else(err).or_else(sq), Ok(2));
assert_eq!(Err(3).or_else(sq).or_else(err), Ok(9));
assert_eq!(Err(3).or_else(err).or_else(err), Err(3));

3.4 返回 Option

3.4.1 ok

  • 有值,返回值;否则返回 None。
  • 源码
代码语言:txt复制
pub fn ok(self) -> Option<T> {
    match self {
        Ok(x) => Some(x),
        Err(_) => None,
    }
}
  • 例子
代码语言:txt复制
let ok: Result<u32, anyhow::Error> = Ok(2);
assert_eq!(ok.ok(), Some(2));

let err: Result<u32, anyhow::Error> = Err(anyhow::anyhow!("error"));
assert_eq!(err.ok(), None);

3.4.r err

  • 有值,则返回 None。
  • 源码
代码语言:txt复制
pub fn err(self) -> Option<E> {
    match self {
        Ok(_) => None,
        Err(x) => Some(x),
    }
}
  • 例子
代码语言:txt复制
let x: Result<u32, &str> = Ok(2);
assert_eq!(x.err(), None);

let x: Result<u32, &str> = Err("Nothing here");
assert_eq!(x.err(), Some("Nothing here"));

4 组合 Option 和 Result

以上处理算子可组合使用。

例子:

代码语言:txt复制
use std::env;

fn double_arg(mut argv: env::Args) -> Result<i32, String> {
    argv.nth(1)
        .ok_or("Please give at least one argument".to_owned())
        .and_then(|arg| arg.parse::<i32>().map_err(|err| err.to_string()))
        .map(|n| 2 * n)
}

fn main() {
    match double_arg(env::args()) {
        Ok(n) => println!("{}", n),
        Err(err) => println!("Error: {}", err),
    }
}

2.4.1 节提到,Option 的 ok_or() 返回值为 Result,所以可用 ok_or() 将 Option 转为 Result,进而可继续使用 Result 的处理算子。

也可以用 Result 的 ok() 或 err() 将 Result 转为 Option。

参考

https://www.jianshu.com/p/ce5bddf4b335

https://wiki.jikexueyuan.com/project/rust-primer/error-handling/option-result.html

0 人点赞