type
status
date
slug
summary
tags
category
icon
password
Prelude:
在写 rust 程序时,Result 和 Option 几乎是我们无法避开的数据结构。我认为比起理解它们的运作机制,首先得迅速搞清楚可以怎么“料理”它们。
礼物的包装
其实不需要把
Option<T>
和 Result<T,E>
想得太复杂:Option
装着我们想要的数据,数据的类型是T
。不过,里面也有可能没有数据(None
)。但无论如何,只要我们关心的东西被包装着,它们都会是Option
。
Result
也装着我们想要的数据,不过,它还附带了另一个“蠢蠢欲动”的附加项E
(Error)。实际上,Result 和 Option 的组合非常频繁,例如Result<Option<T>, E>
。Result
为 Rust 的错误处理提供了强大且统一的规范。
那么,我们该怎么打开礼物盒呢……
拆礼物的时刻总是令人兴奋。
无论是
Option
还是 Result
,我们都可以用 unwrap()
来打开这个包裹。- 如果礼物盒里装的是正常的值,一切顺利,皆大欢喜。
- 但如果里面装的是“怪东西”(
None
或Err
),程序就会立刻panic
崩溃。
当然,如果坚持使用更安全的开箱方式(比如
unwrap_or
、match
等),就能自己掌控程序是否会崩溃,这非常实用。礼物盒都提供了哪些功能?
让我们快速过一遍它们提供的方法。详细的解释就不在这里提供了,相信你们能通过 https://doc.rust-lang.org/std/option/ 和 https://doc.rust-lang.org/std/result/ 来查询相关信息。
Option
API | 作用 | 返回值和备注 |
is_some() | 判断是否为 Some | bool |
is_none() | 判断是否为 None | bool |
unwrap() | 获取 Some 内部的值,若为 None 则触发 panic | T / panic |
unwrap_or(default) | 获取值,若为 None 则返回指定的默认值 | T / default |
unwrap_or_else(f) | 获取值,若为 None 则调用闭包 f 返回默认值 | T / default |
map(f) | 若为 Some ,则对内部值调用 f ,返回新的 Option | Option |
and_then(f) | 若为 Some ,则调用 f ,返回另一个 Option | Option |
or(other) | 若为 None ,则返回参数 other ,否则返回自身 | None/T |
or_else(f) | 若为 None ,则调用闭包 f 返回一个 Option | Option |
as_ref() | 将 Option<T> 转换为内部值的不可变引用 Option<&T> | Option<&T> |
as_mut() | 将 Option<T> 转换为内部值的可变引用 Option<&mut T> | Option<&mut T> |
ok_or(err) | 将 Some(value) 转换为 Ok(value) ,而 None 转换为 Err(err) | Result |
ok_or_else(f) | 同上,但如果是 None 则会调用闭包 | Result |
expect(str&) | 跟 unwrap() 相似,但可以自定义错误消息 | T / panic |
? | 在 None 时直接返回 None (需在返回类型为 Option 的函数中使用) | T / none |
值得注意的方法:
map(f)
提供了不需要解包也能操作内部数据的方法,十分常用
expect("Hi")
可以在 panic 时显示错误信息,比unwarp()
更加实用
?
可以极大程度地提高代码的整洁性
is_some()
和is_none()
在做判断时也十分好用
Result
比起直观易懂的
Option
,Result
看似多带了一个类型会比较“绕”,
但本质上它和 Option
是几乎一致的:如果没拿到值(可能是出错了),应该怎么处理。API | 作用 | 返回值 / 备注 |
is_ok() | 判断是否为 Ok | bool |
is_err() | 判断是否为 Err | bool |
unwrap() | 获取 Ok 内部的值,若为 Err 则 panic | T / panic |
unwrap_or(default) | 获取值,若为 Err 则返回默认值 | T / default |
unwrap_or_else(f) | 获取值,若为 Err 则调用闭包 f 返回默认值 | T / default |
map(f) | 若为 Ok ,对内部值调用 f ,返回新的 Result | Result<U, E> |
and_then(f) | 若为 Ok ,调用 f ,返回另一个 Result | Result<U, E> |
map_err(f) | 若为 Err ,对错误调用 f ,返回新的 Result | Result<T, F> |
or(other) | 若为 Err ,返回 other ,否则返回自身 | Result<T, E> |
or_else(f) | 若为 Err ,调用闭包 f 返回 Result | Result<T, E> |
as_ref() | 转为不可变引用 | Result<&T, &E> |
as_mut() | 转为可变引用 | Result<&mut T, &mut E> |
ok() | 成功值 → Some(value) ,错误 → None | Option<T> |
err() | 错误值 → Some(error) ,成功 → None | Option<E> |
? | 遇到 Err 提前返回(需在返回 Result 的函数中使用) | T / err |
Result
也有:map(f)
和 ?
,以及好用的 is_ok()
和 is_err()
在
Result<T, E>
中:T
是成功时返回的值的类型(例如文件内容、计算结果等)。
E
是错误时返回的值的类型(例如std::io::Error
、自定义错误枚举等)。
- 实际上:
E
可以是任意类型,没有限制- 但是为了能用
?
、方便调试和打印,E
通常要实现Debug
、Display
、Error
等trait
- 是的,
E
可以是很复杂的类型(携带上下文、提供辅助方法),也可以是非常简单的错误结构。而Err
只是Result
用来标记“这是错误分支”的外壳,里面装着E
实例
- 作者:Parker Chen
- 链接:www.parkerchenca.com/article/24bf0ccf-d7f8-8055-a11f-fb71bd49d576
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。