Site cover image
Elixir エラーハンドリング構文try~catchとtry~rescueの違い

エラーハンドリング構文と言えばJavaScriptではtry~catch, Rubyではbegin~rescue, Pythonではtry~except があります。

そう、多くの言語でエラーハンドリング構文は1つです。しかしElixirには2種類のエラーハンドリング構文があります(!?)。

それはタイトルにもある通りtry~catchtry~rescueです。

このエントリでは2種類のエラーハンドリング構文try~catchtry~rescueにどんな違いがあるのか説明します。

Elixirでは前提としてexample/1というメソッドは{:ok, result}{:error, reason}を返すように設計します。

case example(foo) do
  {:ok, result} -> # do_something
  {:error, reason} -> # do_something
end

戻り値としてエラーを返すのはGoに似ていますね。

result だけを返すかエラーを発生させるメソッドはメソッド名の末尾に!を付けて定義します。

result = example!(foo)

example!/1がエラーを発生させた場合、エラーをキャッチしなければプログラムは終了します。

ではエラーをキャッチするにはtry~catchtry~rescueのどちらを使えば良いでしょうか?

そのためにはまずElixirにおける2つのエラー発生方法を知る必要があります。

Elixirではエラーを発生させる方法としてthrow/1raiseがあります。

throw/1は、ある値を投げ、キャッチするために使います。が、あまり使うことはないようです。

実際には新しいElixirコードでこれらを使うのは非常にまれです

throw/1で投げた値はtry~catchで捕捉することができます。

try do
  throw(1)
catch
  x -> "Caught: #{x}"
end

またtry~catchではexitも捕捉できます。

通常、明示的にエラーを発生させたいときはraise/1raise/2を使います。

raise "Oh no!"
raise ArgumentError, message: "the argument value is invalid"

raiseで発生させたエラーや、その他のランタイムエラーはtry~rescueを使って捕捉することができます。

try do
  do_something!(foo)
rescue
  e in ArgumentError -> IO.puts("the argument value is invalid")
  e -> IO.puts("error: " <> inspect(e))
end

またRubyのensure, Pythonのfinallyに相当するafter句もあります。

このエントリではElixirのエラーハンドリング構文try~catchtry~rescueの違いを説明しました。

私はその違いを理解しないまま本番にコードを反映してしまって...というのをやったことがあります。

外部ライブラリを使う際などは、中でthrow/1が使われているのか、raiseが使われているのか気を付けてください。

参考文献

Thank you!
Thank you!
URLをコピーしました

コメントを送る

コメントはブログオーナーのみ閲覧できます