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)。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。