當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


Elixir Kernel.SpecialForms.try用法及代碼示例


Elixir語言中 Kernel.SpecialForms.try 相關用法介紹如下。

用法:

try(args)
(宏)

評估給定的表達式並處理可能發生的任何錯誤、退出或拋出。

例子

try do
  do_something_that_may_fail(some_arg)
rescue
  ArgumentError ->
    IO.puts("Invalid argument given")
catch
  value ->
    IO.puts("Caught #{inspect(value)}")
else
  value ->
    IO.puts("Success! The result was #{inspect(value)}")
after
  IO.puts("This is printed regardless if it failed or succeeded")
end

rescue 子句用於處理異常,而catch 子句可用於捕獲拋出的值和退出。 else 子句可用於根據表達式的結果控製流。 catchrescueelse 子句基於模式匹配工作(類似於 case 特殊形式)。

try/1 內部的調用不是尾遞歸的,因為 VM 需要保留堆棧跟蹤以防發生異常。要檢索堆棧跟蹤,請訪問 rescuecatch 子句中的 __STACKTRACE__/0

rescue 子句

除了依賴模式匹配之外,rescue 子句還為異常提供了一些便利,允許人們通過異常的名稱來挽救異常。以下所有格式都是 rescue 子句中的有效模式:

# Rescue a single exception without binding the exception
# to a variable
try do
  UndefinedModule.undefined_function
rescue
  UndefinedFunctionError -> nil
end

# Rescue any of the given exception without binding
try do
  UndefinedModule.undefined_function
rescue
  [UndefinedFunctionError, ArgumentError] -> nil
end

# Rescue and bind the exception to the variable "x"
try do
  UndefinedModule.undefined_function
rescue
  x in [UndefinedFunctionError] -> nil
end

# Rescue all kinds of exceptions and bind the rescued exception
# to the variable "x"
try do
  UndefinedModule.undefined_function
rescue
  x -> nil
end

Erlang 錯誤

Erlang 錯誤在救援時會轉化為 Elixir 錯誤:

try do
  :erlang.error(:badarg)
rescue
  ArgumentError -> :ok
end
#=> :ok

最常見的 Erlang 錯誤將轉化為它們的 Elixir 對應錯誤。那些不是將被轉換為更通用的 ErlangError

try do
  :erlang.error(:unknown)
rescue
  ErlangError -> :ok
end
#=> :ok

事實上, ErlangError 可用於挽救任何不是正確 Elixir 錯誤的錯誤。例如,它也可用於在轉換之前挽救早期的:badarg 錯誤:

try do
  :erlang.error(:badarg)
rescue
  ErlangError -> :ok
end
#=> :ok

catch 子句

catch 子句可用於捕獲拋出的值、退出和錯誤。

捕獲拋出的值

catch 可用於捕獲 Kernel.throw/1 拋出的值:

try do
  throw(:some_value)
catch
  thrown_value ->
    IO.puts("A value was thrown: #{inspect(thrown_value)}")
end

捕捉任何類型的值

catch 子句還支持捕獲退出和錯誤。為此,它允許匹配捕獲值的 kind 以及值本身:

try do
  exit(:shutdown)
catch
  :exit, value ->
    IO.puts("Exited with value #{inspect(value)}")
end

try do
  exit(:shutdown)
catch
  kind, value when kind in [:exit, :throw] ->
    IO.puts("Caught exit or throw with value #{inspect(value)}")
end

catch 子句還支持 :error 以及 :exit:throw,就像在 Erlang 中一樣,盡管通常會避免這種情況以支持 raise /rescue 控製機製。原因之一是當捕獲 :error 時,錯誤不會自動轉換為 Elixir 錯誤:

try do
  :erlang.error(:badarg)
catch
  :error, :badarg -> :ok
end
#=> :ok

after 子句

after 子句允許您定義將在傳遞給 try/1 的代碼塊成功以及引發錯誤時調用的清理邏輯。請注意,當接收到導致其突然退出的退出信號時,該進程將照常退出,因此不能保證執行after 子句。幸運的是,Elixir 中的大多數資源(例如打開的文件、ETS 表、端口、套接字等)都鏈接到或監視擁有的進程,並且如果該進程退出,它們會自動清理自己。

File.write!("tmp/story.txt", "Hello, World")
try do
  do_something_with("tmp/story.txt")
after
  File.rm("tmp/story.txt")
end

else 子句

else 子句允許傳遞給 try/1 的主體結果在以下位置進行模式匹配:

x = 2
try do
  1 / x
rescue
  ArithmeticError ->
    :infinity
else
  y when y < 1 and y > -1 ->
    :small
  _ ->
    :large
end

如果 else 子句不存在且未引發異常,則將返回表達式的結果:

x = 1
^x =
  try do
    1 / x
  rescue
    ArithmeticError ->
      :infinity
  end

但是,如果存在 else 子句但表達式的結果與任何模式都不匹配,則會引發異常。此異常不會被同一 try 中的 catchrescue 捕獲:

x = 1
try do
  try do
    1 / x
  rescue
    # The TryClauseError cannot be rescued here:
    TryClauseError ->
      :error_a
  else
    0 ->
      :small
  end
rescue
  # The TryClauseError is rescued here:
  TryClauseError ->
    :error_b
end

同樣,else 子句中的異常不會在同一個 try 中被捕獲或拯救:

try do
  try do
    nil
  catch
    # The exit(1) call below can not be caught here:
    :exit, _ ->
      :exit_a
  else
    _ ->
      exit(1)
  end
catch
  # The exit is caught here:
  :exit, _ ->
    :exit_b
end

這意味著 VM 不再需要在 else 子句中保留一次堆棧跟蹤,因此當使用帶有尾調用的 try 作為 else 子句中的最終調用時,尾遞歸是可能的。 rescuecatch 子句也是如此。

隻有嘗試過的表達式的結果才落入else 子句。如果 try 最終出現在 rescuecatch 子句中,則它們的結果不會下降到 else

try do
  throw(:catch_this)
catch
  :throw, :catch_this ->
    :it_was_caught
else
  # :it_was_caught will not fall down to this "else" clause.
  other ->
    {:else, other}
end

變量處理

由於try 中的表達式可能由於異常而未被計算,因此在try 中創建的任何變量都不能被外部訪問。例如:

try do
  x = 1
  do_something_that_may_fail(same_arg)
  :ok
catch
  _, _ -> :failed
end

x
#=> unbound variable "x"

在上麵的示例中,無法訪問 x,因為它是在 try 子句中定義的。解決此問題的常見做法是返回在 try 中定義的變量:

x =
  try do
    x = 1
    do_something_that_may_fail(same_arg)
    x
  catch
    _, _ -> :failed
  end

相關用法


注:本文由純淨天空篩選整理自elixir-lang.org大神的英文原創作品 Kernel.SpecialForms.try(args)。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。