
Rust Result Option 链式调用
设计哲学
将可能性编码到类型系统中:Rust 的 Result
和 Option
类型允许在编译时捕获错误和空值,避免运行时的「空指针」调用。
在很多语言中,null 的存在带来了大量的运行时错误(比如著名的 NullPointerException)。函数返回一个特殊值(如 -1)来表示错误,也常常导致开发者忘记检查从而引发 bug。
Rust 通过 Option
-
Option<T>
代表一个值可能存在,也可能不存在。 -
Result<T, E>
代表一个操作可能成功,也可能失败。
Option
Option<T>
是一个枚举(Enum),它有两个变体:
-
Some(T)
: 表示值存在,T 就是那个具体的值。 -
None
: 表示值不存在。
Result
Result<T, E>
也是一个枚举,它有两个变体:
-
Ok(T)
: 操作成功,T 是成功的值。 -
Err(E)
: 操作失败,E 是错误信息。
链式调用
这里把 Result 和 Option 放到一起说,因为大多数链式调用从语义上是相同的,一起说更容易理解。至于有一些 Option 或 Result 独有的方法则单独拎出来说。
下面把 None 和 Err 统称为「无值「,Some 和 Ok 统称为「有值」,Result 和 Option 统称为容器类型,原值类型为 T,新值类型为 U。下面会根据我认为的语义来把链式调用分为几个类:
无值则 Panic!
此类方法在无值时会直接 panic,通常用于调试或开发者确认某个值一定存在的场景。
方法 | Result 签名 | Option 签名 | 描述 |
---|---|---|---|
unwrap |
fn(self) -> T | fn(self) -> T | 获取 Option 或 Result 中的值,如果值不存在或操作失败,则会 panic。 |
expect |
fn(self, msg: &str) -> T | fn(self, msg: &str) -> T | 类似于 unwrap ,但可以提供自定义的错误信息。 |
unwrap_or |
fn(self, default: T) -> T | fn(self, default: T) -> T | 获取值,如果无值返回提供的默认值。 |
unwrap_or_else |
fn(self, op: F) -> T | fn(self, op: F) -> T | 获取值,如果无值调用闭包返回默认值。 |
unwrap_or_default |
fn(self) -> E | N / A | 获取值,如果无值返回类型的默认值。 |
转换 - Mapping
此类方法用于将值从一个类型 T 转换成另外一个类型 U。不同之处仅在于当无值时的处理方式。
方法 | Result 签名 | Option 签名 | 描述 |
---|---|---|---|
map |
fn(self, op: F) -> Option | fn(self, op: F) -> Option | 如果有值,则将内部值 T 通过闭包转换 U。返回类型为容器。 |
map_or |
fn(self, default: T, op: F) -> T | fn(self, default: U, op: F) -> U | 如果有值,则 T 转 U,如果无值,则返回默认值 U,返回类型为 U。 |
map_or_else |
fn(self, default: F, op: F) -> T | fn(self, default: F, op: F) -> T | 如果有值,则 T 转 U,如果无值,则调用另一个闭包返回 U,返回类型为 U。 |
链式调用
此类方法类似于 if 条件分支,可以针对有值或无值的情况继续写逻辑从而避免大量的类似 if Some(T) = F() { ... }
这样的条件判断。
方法 | Result 签名 | Option 签名 | 描述 |
---|---|---|---|
and |
fn(self, res: Result<U, E>) -> Result<U, E> | fn(self, opt: Option) -> Option | 如果有值,则返回另一个容器类型,否则返回无值。 |
and_then |
fn(self, op: F) -> Result<U, E> | fn(self, op: F) -> Option | 如果有值,则将内部值 T 通过闭包转换 U,返回类型为容器。无值则继续返回无值容器 |
or |
fn(self, res: Result <U, E>) -> Result<T, E> | fn(self, opt: Option) -> Option |
如果有值,则返回当前容器类型,否则返回另一个容器类型。 |
or_else |
fn(self, op: F) -> Result<T, E> | fn(self, op: F) -> Option |
如果有值,则返回当前容器类型,否则调用闭包返回另一个容器类型。 |
filter |
fn(self, op: F) -> Result<T, E> | fn(self, op: F) -> Option |
如果有值且满足条件,则返回当前容器类型,否则返回无值。 |
Option Result 互转
有时我们需要将 Option
和 Result
互相转换,这些方法可以帮助我们完成这种转换。
方法 | Result 签名 | Option 签名 | 描述 |
---|---|---|---|
ok |
fn(self) -> Option |
N / A | 将 Result 转换为 Option ,如果是 Ok 则返回 Some(T) ,否则返回 None 。 |
err |
fn(self) -> Option |
N / A | 将 Result 转换为 Option ,如果是 Err 则返回 Some(E) ,否则返回 None 。 |
ok_or |
fn(self, default: T) -> Result<T, E> | N / A | 将 Option 转换为 Result ,如果是 Some(T) 则返回 Ok(T) ,否则返回 Err(default) 。 |
ok_or_else |
fn(self, op: F) -> Result<T, E> | N / A | 将 Option 转换为 Result ,如果是 Some(T) 则返回 Ok(T) ,否则调用闭包返回 Err 。 |
总结
传统的错误处理(如 if err != nil
)是一种「控制流」思想。你需要在代码的 Happy Path(成功路径)中穿插各种错误检查的分支。
Rust 的 Option
和 Result
及其组合子(combinators, 如 map
, and_then
)鼓励你用「数据流」的思维来编程。你可以想象数据在一个管道里流动,这个管道有两个轨道:Some/Ok
轨道和 None/Err
轨道。
map
, and_then
等操作是在 Some/Ok
轨道上对数据进行加工。
一旦任何一个环节出错,数据就会切换到 None/Err
轨道,并一直走到终点。
or_else
像是提供了一个从 None/Err
轨道切换回 Some/Ok
轨道的机会。
这种模型(有时被称为「铁路导向编程」)让你的主逻辑非常清晰,错误处理被优雅地链接在一起,而不是打断主逻辑。