13
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ElixirAdvent Calendar 2022

Day 23

今日のElixirSchoolメモ18「エラーハンドリング」

Last updated at Posted at 2022-12-24

Elixir Schoolの勉強メモです。

一般的な規則

  • 関数の通常の操作の一部であるエラー(ユーザーが間違った入力をした場合など)の場合、関数はそれに応じて {:ok, result}{:error, reason} を返す
  • 通常の操作の一部では無いエラー(構成データを解析できないなど)の場合は、例外をスローする。

通常、標準エラーはパターンマッチで処理する。

エラーハンドリング

raise/1raise/2でエラーを発生させることができる。

iex(4)> raise "Oh no!"
** (RuntimeError) Oh no!
iex(4)> raise ArgumentError, message: "the argument value is invalid"
** (ArgumentError) the argument value is invalid

エラーが起きることが分かっている場合、try/reduceというパターンマッチを使ってエラーハンドリングできる。

try do
  raise "Oh no!"
rescue
  e in RuntimeError -> IO.puts("An error occurred: " <> e.message)
end

reduce節で複数のエラーにマッチさせることができる。

After

エラーの有無に関わらず、tru/reduceの後に何らかの処理が必要とする場合、
try/afterが存在する。

iex(5)> try do
...(5)>   raise "Oh no!"
...(5)> rescue
...(5)>   e in RuntimeError -> IO.puts("An error occurred: " <> e.message)
...(5)> after
...(5)>   IO.puts "The end!"
...(5)> end
An error occurred: Oh no!
The end!
:ok

これはファイルや接続が必ず閉じられなければならない場合に最もよく使われる。

新しいエラー

モジュールを作ることで独自の例外を定義することができる。
defexception を使って、例外のいろいろなフィールドをデフォルト値とともに定義できる。

iex(7)> defmodule ExampleError do
...(7)>   defexception message: "an example error has occurred"
...(7)> end
iex(8)> try do
...(8)>   raise ExampleError
...(8)> rescue
...(8)>   e in ExampleError -> e
...(8)> end
%ExampleError{message: "an example error has occurred"}

Throw

throw/1関数を使えば、catchできる特定の値で実行を中断できる。

iex(9)> try do
...(9)>   for x <- 0..10 do
...(9)>     if x == 5, do: throw(x)
...(9)>     IO.puts(x)
...(9)>   end
...(9)> catch
...(9)>   x -> "Caught: #{x}"
...(9)> end
0
1
2
3
4
"Caught: 5"

throw/catchはかなり珍しく、概してライブラリが十分なAPIを提供していない場合の間に合わせとして存在する。

終了

Elixirが提供している最後のエラー処理機構はexit
終了シグナルはプロセスが死に、それがElixirのフォールトトレランスの重要な部分であるときに発せられる。

明示的に終了するにはexit/1を使う。

iex(10)> spawn_link fn -> exit("oh no") end
** (EXIT from #PID<0.106.0>) shell process exited with reason: "oh no"

try/catchで終了を補足できるが、そうすることは非常にまれ。
ほとんど全ての場合ではsupervisiorにプロセスの終了をハンドリングさせるほうが都合がよい。

iex(1)> try do
...(1)>   exit "oh no!"
...(1)> catch
...(1)>   :exit, _ -> "exit blocked"
...(1)> end
"exit blocked"
13
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?