异常追踪
Nim 支持异常追踪。 raises 编译指示可以显式定义过程/迭代器/方法/转换器所允许抛出的异常。编译期会加以验证:
proc p(what: bool) {.raises: [IOError, OSError].} =
if what: raise newException(IOError, "IO")
else: raise newException(OSError, "OS")
空的 raises 列表(raises: [])表示不允许抛出异常:
proc p(): bool {.raises: [].} =
try:
unsafeCall()
result = true
except CatchableError:
result = false
raises 列表也可以附加到过程类型上。这会影响类型兼容性:
type
Callback = proc (s: string) {.raises: [IOError].}
var
c: Callback
proc p(x: string) =
raise newException(OSError, "OS")
c = p # type error
对于例程 p 来说,编译器使用推断规则来判断可能引发的异常的集合; 算法在 p 的调用图上运行:
- 对过程类型 T 的每个间接调用都假定产生 system.Exception (所有异常的基类),即任意异常都有可能,除非 T 拥有显式的 raises 列表。 不过,如果是以 f(…) 的形式调用并且 f 是当前分析的例程的参数,而且并被标记 .effectsOf: f,那么忽略它。 乐观地假定这类调用没有 effect。 第二条规则对这种情况有所补充。
- 当某过程类型的表达式 e 是作为过程 p 的标记为 .effectsOf 的参数传入的,对 e 的调用会被视为间接调用,它的 raises 列表会加入到 p 的 raises 列表。
- 所有对方法体未知(因为声明前置)的过程 q 的调用都会被看作抛出 system.Exception 除非 q 显式定义了 raises 列表。 importc 导入的过程,若没有显式声明 raises 列表,则默认视为 .raises: []。
- 方法 m 每一次调用都假定会抛出 system.Exception,除非显式声明了 raises 列表。
- 对于其他的调用,Nim 可以分析推断出确切的 raises 列表。
- 推断 p 的 raises 列表时,Nim 会考虑它里面的 raise 和 try 语句。
.raises: [] 异常追踪机制不追踪继承自 system.Defect 的异常。这样更能跟内置运算符保持一致。 下面的代码是合法的:
proc mydiv(a, b): int {.raises: [].} =
a div b # 会抛出 DivByZeroDefect 异常
同理,下面的代码也是合法的:
proc mydiv(a, b): int {.raises: [].} =
if b == 0: raise newException(DivByZeroDefect, "除数为 0")
else: result = a div b
这是因为 DivByZeroDefect 继承自 Defect,再加上 --panics:on 选项 Defect 异常就变成了不可修复性错误。(自从 Nim 1.4 开始)
当前内容版权归 vectorworkshopbaoerjie 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 vectorworkshopbaoerjie .