例外
例外は例外的なケースで「スローされる」 単なるヴァリアントの特殊な種類です(乱用はしないように!)。
使い方
let getItem = (theList) =>
if (callSomeFunctionThatThrows()) {
/* 見つかったitemをここで返す */
} else {
raise(Not_found)
};
let result =
try (getItem([1, 2, 3])) {
| Not_found => 0 /* getItemがエラーをスローした場合のデフォルトの値 */
};
上記はデモンストレーション目的のものに過ぎないことに注意してください。実際には、getItem
から直接 option(int)
を返すでしょうし、try
を使うことも避けてください。
関数から別の返り値を取得すると同時に、例外に直接マッチすることができます。
switch (List.find((i) => i === theItem, myItems)) {
| item => print_endline(item)
| exception Not_found => print_endline("No such item found!")
};
ヴァリアントを作るように専用の例外を作ることもできます(例外でも大文字にする必要があります)。
exception InputClosed(string);
...
raise(InputClosed("the stream has closed!"));
ヒントとコツ
普通のヴァリアントがある時は、しばしば例外が必要ないことがあります。 例えば、item
がコレクション内に見つからない時、スローすることの代わりに、option(item)
を返すことを試してください(この場合は None
)。
設計方針
上記の tip は OCaml の標準ライブラリで起こっていることと矛盾しているようです。List や String のようなモジュール内の主要な関数はしばしば過度に例外をスルーするようです。 これは部分的に歴史的な堆積物で、部分的にパフォーマンスのために細心の注意を払っていることによるものです。 ネイティブの OCaml/Reason は信じなれないくらいパフォーマンスが高いです。例外送出は、割当と返却(例えば option
)に比べて非常に(訳注: パフォーマンスコストが)安くなるようにデザインされています。 これは残念ながら JavaScript のためのケースではありません。
より新しい標準ライブラリの代替は、大抵例外を送出するのではなく、 option
を返す関数が同梱しています。 例えば、List.find
は option
を返すバージョンの List.find_opt
があります。これはスローしません。
繰り返しますが、例外は実際にはただのヴァリアントです。 事実、それらはすべて exn
と呼ばれる単一のヴァリアント型に所属しています。 それは、extensible variant のことで、それに InputClosed
のような新しいコンストラクタを追加することを意味しています。 exception Foo
は、コンストラクタを exn
に追加するためのただのシュガーです。