3章あたり。
システムが例外を起こすのは内部エラーが発生した場合と
コードが以下のいずれかを意図的に例外を発生させた場合
呼び出し側が捕捉する可能性がある例外を投げるのに使う。
この場合、関数が例外を投げる可能性があることをドキュメントに明記すること。
この関数を利用する際には2つの選択肢がある
通常の場合だけを考えてプログラムを書き、例外を知らんぷりするか、
もしくは呼び出しをtry . . . catch 式でくるんでエラーを処理するか。
この関数は現在のプロセスを本当に終了させたい場合に使う。
この例外が捕捉されないと、現在のプロセスにリンクされているすべてのプロセスに
{’EXIT’,Pid,Why} メッセージがブロードキャストされる。
「クラッシュエラー」を示すために使う。
クラッシュエラーとは、呼び出し側が処理できなさそうなまずい状況をいう。
このエラーは内部的に発生したエラーと同じレベル。
- 関数の呼び出しをtry...catch式でくるむ方法
- 関数の呼び出しをcatch式でくるむ方法
- afterキーワードの後のコードはFuncOrExpressionSeqの後始末するのに使われる
- afterは例外が起こった場合でも実行されることが保証される
- afterセクションは省略できる
try FuncOrExpressionSeq of
Pattern1 [when Guard1] -> Expressions1;
Pattern2 [when Guard2] -> Expressions2;
...
catch
ExceptionType1: ExPattern1 [when ExGuard1] -> ExExpressions1;
ExceptionType2: ExPattern2 [when ExGuard2] -> ExExpressions2;
...
after
AfterExpressions
end
catchの方が問題の原因を解析する過程の多く情報がある
・try_test.erl
-module(try_test).
-export([demo1/0, demo2/0]).
generate_exception(1) -> a;
generate_exception(2) -> throw(a);
generate_exception(3) -> exit(a);
generate_exception(4) -> {'EXIT', a};
generate_exception(5) -> erlang:error(a).
demo1() ->
[catcher(I) || I <- [1,2,3,4,5]].
demo2() ->
[{I, (catch generate_exception(I))} || I <- [1,2,3,4,5]].
catcher(N) ->
try generate_exception(N) of
Val -> {N, normal, Val}
catch
throw:X -> {N, caught, thrown, X};
exit:X -> {N, caught, exited, X};
error:X -> {N, caught, error, X}
end.
・Eshell
1> c(try_test).
{ok,try_test}
2> try_test:demo1().
[{1,normal,a},
{2,caught,thrown,a},
{3,caught,exited,a},
{4,normal,{'EXIT',a}},
{5,caught,error,a}]
3> try_test:demo2().
[{1,a},
{2,a},
{3,{'EXIT',a}},
{4,{'EXIT',a}},
{5,
{'EXIT',{a,[{try_test,generate_exception,1,
[{file,"try_test.erl"},{line,8}]},
{try_test,'-demo2/0-lc$^0/1-0-',1,
[{file,"try_test.erl"},{line,14}]},
{try_test,'-demo2/0-lc$^0/1-0-',1,
[{file,"try_test.erl"},{line,14}]},
{erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,674}]},
{shell,exprs,7,[{file,"shell.erl"},{line,686}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,641}]},
{shell,eval_loop,3,[{file,"shell.erl"},{line,626}]}]}}}]
「一般的な場合」がない関数ならば{ok, Value} や{error, Reason} のようなものを返す。
ただこの方法だと、呼び出し側は戻り値に対して必ず何らかの対応をしなければならなくなる。
そこで、次に挙げる2つの方法のうちのどちらかを使うべき
...
case f(X) of
{ok, Val} ->
do_some_thing_with(Val);
{error, Why} ->
%% ... エラーを処理する...
end,
...
この方法では両方の場合の戻り値を調べる
...
{ok, Val} = f(x),
do_some_thing_with(Val);
...
f(x)が(error, ...)を返すと例外が起こる
エラーを処理することになっているコードは以下のように書く
try my_func(X)
catch
throw:{thisError, X} -> ...
throw:{someOtherError, X} -> ...
end
ありうる例外をすべて捕捉したい場合は次のようなイディオムを使う
_が何にでも一致することを利用している
try Expr
catch
_:_ -> ...例外をすべて処理するコード ..
end
タグを省略して次のように書くと、
try Expr
catch
_ -> ... 例外をすべて処理するコード...
end
この場合はデフォルトタグとしてthrow が仮定されるから
エラーをすべて捕捉することはできない。
※ 例外を捕捉した場合、erlang:get_stacktrace() を呼び出せば最新のスタックトレースを知ることができる