Exception
例外只是個特別的變異類型,在異常地情況下"丟出"(請不要濫用!)。
用法
let getItem = (theList) =>
if (callSomeFunctionThatThrows()) {
/* return the found item here */
} else {
raise(Not_found)
};
let result =
try (getItem([1, 2, 3])) {
| Not_found => 0 /* Default value if getItem throws */
};
注意上述只是展示目的;實際上,你應該直接從 getItem
傳回 option(int)
並且避免一起使用 try
。
你可以直接匹配例外,同時從別的函式獲得傳回值:
switch (List.find((i) => i === theItem, myItems)) {
| item => print_endline(item)
| exception Not_found => print_endline("找不到項目!")
};
你也可以像是新增變異一樣新增自己的例外(例外也必須是字母大寫)。
exception InputClosed(string);
...
raise(InputClosed("串流已關閉!"));
提示 & 技巧
當你有普通變異,通常不需要例外。 例如,當集合中找不到 item
時,試著傳回 option(item)
(這個例子傳回None
),取而代之丟出例外。
設計決策
上述提示看似否定 OCaml 標準函式庫內所發生的事情;如 List 和 String 模組內顯著的函式看起來過度地使用例外。 這一部份是歷史沈澱物,另一部份是極度在意效率。 原生 OCaml/Reason 是非常有效率;丟出例外的設計是非常廉價的,比配置和傳回還要廉價,例如 option
。 很不幸在 JavaScript 沒有這個問題。
較新的標準函式庫通常帶有傳回 option
的函式,而非丟出例外。 例如,List.find
有傳回 option
的相似物 List.find_opt
,不會丟出例外。
實際上例外也是個變異。 事實上,它們都屬於單一變異,稱之為 exn
。 這是個可擴充的變異,表示你可以加入新的建構子,例如上述的 InputClosed
。 exception Foo
只是個語法糖,方便加入建構子到 exn
。