# 结果
Result 是 Deft 显式的成功/失败值:成功为 `%Ok{ :value v }`,
失败为 `%Err{ :message m }`。两者都是带标签映射,因此字段访问
(`$r~value`、`$r~message`)和模式匹配可直接作用于它们。下面这些
裸函数用于构造、检查和解包 Result,并已编译进每个运行时——无需
导入。围绕 `try`/`catch` 和返回 Result 函数的语言约定,参见
错误处理。
## 函数
| 函数 | 用途 |
|---|---|
| `ok value` | 构造 `%Ok{ :value value }` |
| `err message` | 构造 `%Err{ :message message }` |
| `ok? x` | `x` 为 `%Ok` 时返回 true |
| `err? x` | `x` 为 `%Err` 时返回 true |
| `unwrap result ?default` | 提取 `%Ok` 的 `:value`、`%Err` 的 `:message`,或给定时的 `default` |
| `throw value` | 抛出错误,跳转到最近的外层 `try` |
| `ok! expr` / `$expr(ok!)` | 断言 `%Ok` 并返回其 `:value`;遇到 `%Err` 时从外层函数返回 |
| `err! expr` / `$expr(err!)` | 断言 `%Err` 并返回其 `:message`;遇到 `%Ok` 时从外层函数返回 |
`[ok v]` 等价于字面量 `%Ok{ value v }`,`[err m]` 等价于
`%Err{ message m }`;需要包装计算出的值时,这些构造函数很方便。
`unwrap` 返回 `%Ok` 的 `:value`;对于 `%Err`,它返回提供的默认值,
未提供默认值时返回 `:message`。默认值只在失败时使用,非 Result 值
原样通过。
`throw` 接受任意值。字符串是惯用形式,也是 catch 绑定的内容;抛出
完整的 `%Err` 映射可以保留额外字段:
[throw "not found"] [throw %Err{ :message "invalid input" :code 422 }]
`ok!` 和 `err!` 由编译器拦截:`[ok! $expr]` 和后缀形式 `$expr(ok!)`
都会发出内联操作码而非函数调用,因此它们必须出现在函数体内,短路
返回才有意义。非 Result 值经过这两个动词时原样通过。
命名空间辅助函数 `result/map`、`result/sequence` 和
`result/traverse` 将函数提升到 Result 之上,并折叠 Result 集合;
`and-then` 是单子绑定。它们都在参考文档中按符号逐一记录。
## 示例
def fetch-user {|id^number| if ($id < 0) { return [err "bad id"] } [ok %{ :id $id :name "Alice" }] } set r [fetch-user 7] [ok? $r] # => true [err? $r] # => false $r~value~name # => "Alice"
用谓词分支,或用 `match` 解构:
if [ok? $r] { echo "name:" $r~value~name } else { echo "failed:" $r~message } match $r { %Ok{ value $v } => echo "got $v" %Err{ message $m } => echo "error: $m" }
`unwrap` 是最快捷的出口;双参数形式为 `%Err` 提供默认值:
[unwrap [ok 42]] # => 42 [unwrap [err "nope"]] # => "nope" — the message [unwrap [err "nope"] 0] # => 0 — the default $r(unwrap) # => %{ :id 7 :name "Alice" }
`ok!` 解包或从外层函数提前返回——这是让 Result 沿顺利路径串联的
惯用方式:
def inc-or-fail {|x| if ($x > 100) { return [err "too big"] } else { return [ok ($x + 1)] } } def go {|x| set v [ok! [inc-or-fail $x]] # on %Err, go returns that Err ($v * 10) } [go 4] # => 50 [go 200] # => %Err{:message "too big"}
`err!` 是它的镜像:断言失败并提取消息,当值为 `%Ok` 时提前返回:
def describe {|r| set msg [err! $r] # on %Ok, describe returns that Ok [str "failed: " $msg] } [describe [err "disk full"]] # => "failed: disk full" [describe [ok 42]] # => %Ok{:value 42}
`try` 内的 `throw` 将控制权交给 catch:
try { [throw "x must be non-negative"] } catch e { echo "caught:" $e # caught: x must be non-negative }