错误处理

2022-01-05 09:58:08 浏览数 (2)

计算 M 表达式的结果会产生以下结果之一:

  • 产生单个值。
  • 出现错误,表明对表达式求值的过程无法产生值。错误包含单个记录值,可用于提供有关导致评估不完整的原因的附加信息。

错误可以从表达式中引发,也可以从表达式中处理。

引发错误

引发错误的语法如下:

错误引发表达式: error 表达式

文本值可用作错误值的简写。例如:

复制

代码语言:javascript复制
error "Hello, world" // error with message "Hello, world"

完整的错误值是记录,可以使用以下Error.Record函数构造:

复制

代码语言:javascript复制
error Error.Record("FileNotFound", "File my.txt not found",
     "my.txt")

上面的表达式等价于:

复制

代码语言:javascript复制
error [ 
    Reason = "FileNotFound", 
    Message = "File my.txt not found", 
    Detail = "my.txt" 
]

引发错误将导致当前表达式计算停止,并且表达式计算堆栈将展开,直到发生以下任一情况:

  • 到达记录字段、部分成员或 let 变量——统称为一个条目。该条目被标记为有错误,错误值与该条目一起保存,然后传播。对该条目的任何后续访问都将导致引发相同的错误。记录、节或 let 表达式的其他条目不一定会受到影响(除非它们访问先前标记为有错误的条目)。
  • 达到了顶级表达式。在这种情况下,评估顶级表达式的结果是错误而不是值。
  • try达到了一个表达式。在这种情况下,错误被捕获并作为值返回。

处理错误

一个错误处理表达式是用来处理一个错误:

_error-handling-expression: try protected-expression other-clause opt protected-expression:       expression other-clause: otherwise default-expression default-expression:       expression

的评价时以下成立错误处理表达没有otherwiseclause

  • 如果protected-expression 的求值没有导致错误并产生值x,则error-handling-expression 产生的值是以下形式的记录:

复制

代码语言:javascript复制
    [ HasErrors = false, Value = x ]
  • 如果受保护表达式的求值产生错误值 e,则错误处理表达式的结果是以下形式的记录:

复制

代码语言:javascript复制
    [ HasErrors = true, Error = e ]

的评价时以下成立错误处理表达otherwiseclause

  • 必须在其他子句之前评估受保护的表达式。
  • 当且仅当对受保护表达式的求值引发错误时,必须对其他子句求值。
  • 如果protected-expression的求值引发错误,则error-handling-expression产生的值是对others-clause 求值的结果。
  • 传播在其他条款评估期间引发的错误。

以下示例说明了未引发错误的情况下的错误处理表达式

复制

代码语言:javascript复制
let
    x = try "A"
in
    if x[HasError] then x[Error] else x[Value] 
// "A"

以下示例显示引发错误然后处理它:

复制

代码语言:javascript复制
let
    x = try error "A" 
in
    if x[HasError] then x[Error] else x[Value] 
// [ Reason = "Expression.Error", Message = "A", Detail = null ]

可以使用 else 子句将 try 表达式处理的错误替换为替代值:

复制

代码语言:javascript复制
try error "A" otherwise 1 
// 1

如果 else 子句也引发错误,那么整个 try 表达式也会引发错误:

复制

代码语言:javascript复制
try error "A" otherwise error "B" 
// error with message "B"

记录错误和 let 初始值设定项

以下示例显示了一个记录初始值设定项,其字段A引发错误并由其他两个字段B和访问C。FieldB不处理由 引发的错误A,但C会处理。final 字段D不会访问A,因此它不受A.

复制

代码语言:javascript复制
[ 
    A = error "A", 
    B = A   1,
    C = let x =
            try A in
                if not x[HasError] then x[Value]
                else x[Error], 
    D = 1   1 
]

对上述表达式求值的结果是:

复制

代码语言:javascript复制
[ 
    A = // error with message "A" 
    B = // error with message "A" 
    C = "A", 
    D = 2 
]

M 中的错误处理应该在接近错误原因的地方执行,以处理延迟字段初始化和延迟闭包评估的影响。以下示例显示了使用try表达式处理错误的失败尝试:

复制

代码语言:javascript复制
let
    f = (x) => [ a = error "bad", b = x ],
    g = try f(42) otherwise 123
in 
    g[a]  // error "bad"

在此示例中,定义g旨在处理调用f. 但是,该错误是由字段初始值设定项引发的,该初始值设定项仅在需要时运行,因此在从 f 返回记录并通过try表达式之后。

未实现错误

在开发表达式时,作者可能希望省略表达式某些部分的实现,但仍希望能够执行表达式。处理这种情况的一种方法是为未实现的部分引发错误。例如:

复制

代码语言:javascript复制
(x, y) =>
     if x > y then
         x - y
     else
         error Error.Record("Expression.Error", 
            "Not Implemented")

省略号 ( ...) 可用作 的快捷方式error

未实现的表达式: ...

例如,以下等效于前面的示例:

复制

代码语言:javascript复制
(x, y) => if x > y then x - y else ...

0 人点赞