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
子句可用於根據表達式的結果控製流。 catch
、 rescue
和 else
子句基於模式匹配工作(類似於 case
特殊形式)。
內部的調用不是尾遞歸的,因為 VM 需要保留堆棧跟蹤以防發生異常。要檢索堆棧跟蹤,請訪問 try/1
rescue
或 catch
子句中的
。__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
事實上,
可用於挽救任何不是正確 Elixir 錯誤的錯誤。例如,它也可用於在轉換之前挽救早期的ErlangError
: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
中的 catch
或 rescue
捕獲:
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
子句中的最終調用時,尾遞歸是可能的。 rescue
和 catch
子句也是如此。
隻有嘗試過的表達式的結果才落入else
子句。如果 try
最終出現在 rescue
或 catch
子句中,則它們的結果不會下降到 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 Kernel.SpecialForms.case用法及代碼示例
- Elixir Kernel.SpecialForms.%{}用法及代碼示例
- Elixir Kernel.SpecialForms.for用法及代碼示例
- Elixir Kernel.SpecialForms.quote用法及代碼示例
- Elixir Kernel.SpecialForms.require用法及代碼示例
- Elixir Kernel.SpecialForms.&expr用法及代碼示例
- Elixir Kernel.SpecialForms.<<args>>用法及代碼示例
- Elixir Kernel.SpecialForms.{args}用法及代碼示例
- Elixir Kernel.SpecialForms.unquote_splicing用法及代碼示例
- Elixir Kernel.SpecialForms.receive用法及代碼示例
- Elixir Kernel.SpecialForms.%struct{}用法及代碼示例
- Elixir Kernel.SpecialForms.import用法及代碼示例
- Elixir Kernel.SpecialForms.left . right用法及代碼示例
- Elixir Kernel.SpecialForms.alias用法及代碼示例
- Elixir Kernel.SpecialForms.fn用法及代碼示例
- Elixir Kernel.SpecialForms.cond用法及代碼示例
- Elixir Kernel.SpecialForms.__aliases__用法及代碼示例
- Elixir Kernel.SpecialForms.left :: right用法及代碼示例
- Elixir Kernel.SpecialForms.unquote用法及代碼示例
- Elixir Kernel.SpecialForms.with用法及代碼示例
- Elixir Kernel.SpecialForms.__block__用法及代碼示例
- Elixir Kernel.SpecialForms.^var用法及代碼示例
- Elixir Kernel.round用法及代碼示例
- Elixir Kernel.left / right用法及代碼示例
- Elixir Kernel.put_in用法及代碼示例
注:本文由純淨天空篩選整理自elixir-lang.org大神的英文原創作品 Kernel.SpecialForms.try(args)。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。