异常
异常只是一种特殊的变体,在出现异常的情况下抛出(不要滥用它们!)。
用法
注意,上面的代码只是为了演示;事实上,你可以直接从 getItem
返回一个 option<int>
,并完全避免使用 try
。
你可以在匹配异常的 同时 从函数获取返回值:
你也可以像创建变体一样创建你自己的异常(异常也需要首字母大写)。
捕获 JS 异常
为了区分 JavaScript 异常和 ReScript 异常,ReScript 将 JS 异常限制在 Js.Exn.Error(payload)
变体下。捕获一个从 JS 端抛出的异常:
obj
的类型是 Js.Exn.t
,ReScript 故意让这个类型不透明来阻止一些非法操作。如果要对 obj
进行操作,可以像上面的代码一样使用标准库 Js.Exn
模块中的辅助函数。
抛出一个 JS 异常
raise(MyException)
会引发一个 ReScript 异常。要引发一个 JavaScript 异常(不管你的目的是什么),请使用 Js.Exn.raiseError
:
你可以在 JS 端捕获它:
JS// after importing `myTest`...
try {
myTest()
} catch (e) {
console.log(e.message) // "Hello!"
}
在 JS 中捕获 ReScript 异常
前面的部分没有你想象的那么有用;为了让你的 JS 代码与抛出异常的 ReScript 代码一起工作,后者实际上不需要抛出一个 JS 异常。ReScript 的异常可以被 JS 代码使用!
然后在 JS 中:
JS// after importing `myTest`...
try {
myTest()
} catch (e) {
console.log(e.myMessage) // "Oops!"
console.log(e.Error.stack) // the stack trace
}
注意:
RE_EXN_ID
是一个用于“记录”的内部字段。不要在 JS 端使用它。使用其他的字段。
上面的 BadArgument
异常接受一个内联记录类型。为了符合人体工程学(指用起来更符合直觉),我们将该异常编译为 {RE_EXN_ID, myMessage, Error}
。如果异常接受普通的位置参数,比如标准库的 Invalid_argument("Oops!")
,它只使用一个参数,那么这个参数将被编译为 JS 的字段 _1
,第二个位置参数会编译为_2
,以此类推。
技巧和诀窍
当你有普通的变体时,你往往不需要异常。例如,当 item
在一个集合无法找到时,可以返回一个 option<item>
(这种情况返回 None
)而不是抛出异常。
在一个 catch
子句中同时捕获 ReScript 和 JS 的异常
这在技术上是可行的,但希望你永远不必与这样的代码打交道......