Elixir Exception と try-rescue
概要
Elixir の Exception と try-rescue について。
Exception
Exception の発生
文字列と数値を連結させてエラーを発生させてみます。
iex> "a" <> 1
** (ArgumentError) argument error
RuntimeError の発生
引数なしの raise マクロか、文字列引数のみの raise マクロで
RuntimeError を発生させることができます。
iex> raise
** (RuntimeError)
iex> raise "hogehoge"
** (RuntimeError) hogehoge
RuntimeError の発生
例外を引数にとる raise マクロか、
例外・文字列を引数にとるの raise マクロで
任意の Error を発生させることができます。
iex> raise ArgumentError
** (ArgumentError) argument error
iex> raise ArgumentError, "hogehoge"
** (ArgumentError) hogehoge
try rescue による例外の補足
try / rescue によって例外を補足出来ます。
try do
some_logic
rescue
# Error の返却
e in ArgumentError -> e
e in RuntimeError -> e
end
- サンプル
乱数 1-100 を生成します。
基本は FizzBuzz のルールで返却値を決定しますが、
4の倍数なら RuntimeError
6の倍数なら ArgumentError
を返却します。
※倍数が大きい方が優先されます
30回繰り返して処理結果を確認します。
defmodule ExceptionSample do
def random_raise do
x = :random.uniform(100)
strx = Integer.to_string(x)
cond do
rem(x, 15) == 0 ->
"FizzBuzz" <> strx
rem(x, 6) == 0 ->
raise ArgumentError, strx
rem(x, 5) == 0 ->
"Buzz" <> strx
rem(x, 4) == 0 ->
raise strx
rem(x, 3) == 0 ->
"Fizz" <> strx
true ->
x
end
end
def try_rescue do
try do
ExceptionSample.random_raise
rescue
e in ArgumentError -> e
e in RuntimeError -> e
end
end
def try_rescue_times(0) do
# do nothing
end
def try_rescue_times(n) do
IO.inspect ExceptionSample.try_rescue
try_rescue_times(n - 1)
end
end
ExceptionSample.try_rescue_times(30)
- 出力1回目
"FizzBuzz45"
73
"Buzz95"
"Fizz51"
%RuntimeError{message: "32"}
"FizzBuzz60"
%RuntimeError{message: "92"}
67
%ArgumentError{message: "48"}
"FizzBuzz60"
"FizzBuzz15"
"Fizz21"
"Buzz70"
%RuntimeError{message: "16"}
%RuntimeError{message: "56"}
22
46
43
1
"Fizz57"
%ArgumentError{message: "48"}
41
31
%ArgumentError{message: "6"}
58
"Fizz99"
34
19
"Fizz21"
%RuntimeError{message: "4"}
注意
try - rescue はあくまでも例外のための仕組み。
処理フローの制御には利用しないこと。
処理フローの制御に利用したい場合は、
try - throw - catch を利用します。