Appearance
33.2 组合错误类型
利用代数类型系统做错误处理的另外一大好处是可组合性(composability)。比如 Result 类型有这样的一系列成员方法:
rust
fn map<U, F>(self, op: F) -> Result<U, E> where F: FnOnce(T) -> U
fn map_err<F, O>(self, op: O) -> Result<T, F> where O: FnOnce(E) -> F
fn and<U>(self, res: Result<U, E>) -> Result<U, E>
fn and_then<U, F>(self, op: F) -> Result<U, E> where F: FnOnce(T) -> Result<U, E>
fn or<F>(self, res: Result<T, F>) -> Result<T, F>
fn or_else<F, O>(self, op: O) -> Result<T, F> where O: FnOnce(E) -> Result<T, F>
这些方法的签名稍微有点复杂,涉及许多泛型参数。它们之间的区别也就表现在方法签名中。我们可以用下面的方式去掉语法干扰之后,来阅读函数签名,从而理解这些方法之间的区别:
方法 | 方法类型 | 参数类型 |
---|---|---|
map | Result<T, E> -> Result<U, E> | T -> U |
map_err | Result<T, E> -> Result<T, F> | E -> F |
and | Result<T, E> -> Result<U, E> | Result<U, E> |
and_then | Result<T, E> -> Result<U, E> | T -> Result<U, E> |
or | Result<T, E> -> Result<T, F> | Result<T, F> |
or_else | Result<T, E> -> Result<T, F> | E -> Result<T, F> |
通过这个表格的对比,我们可以很容易看出它们之间的区别。比如map
和and_then
的主要区别是闭包参数:map
的参数是做的T -> U
的转换,而and_then
的参数是T -> Result
的转换。Option 类型也有类似的对应的方法,读者可以自己建一个表格,对比一下这些方法签名之间的区别。
下面用一个示例演示一下这些组合函数的用法:
rust
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),
}
}