错误处理( Errors Handling)
Elixir有三种错误机制:错误,抛出和退出。 让我们详细探讨每种机制。
Error
当代码中发生异常事件时,将使用错误(或异常)。 尝试将数字添加到字符串中可以检索样本错误 -
IO.puts(1 + "Hello")
运行上述程序时,会产生以下错误 -
** (ArithmeticError) bad argument in arithmetic expression
:erlang.+(1, "Hello")
这是一个内置错误示例。
提高错误
我们可以使用raise函数raise错误。 让我们考虑一个例子来理解相同的 -
#Runtime Error with just a message
raise "oops" # ** (RuntimeError) oops
通过raise/2传递错误名称和关键字参数列表,可以引发其他错误
#Other error type with a message
raise ArgumentError, message: "invalid argument foo"
您还可以定义自己的错误并提高它们。 考虑以下示例 -
defmodule MyError do
defexception message: "default message"
end
raise MyError # Raises error with default message
raise MyError, message: "custom message" # Raises error with custom message
拯救错误
我们不希望我们的程序突然退出,而是需要仔细处理错误。 为此,我们使用错误处理。 我们使用try/rescue构造来挽救错误。 让我们考虑下面的例子来理解相同的 -
err = try do
raise "oops"
rescue
e in RuntimeError -> e
end
IO.puts(err.message)
运行上述程序时,会产生以下结果 -
oops
我们使用模式匹配处理了救援声明中的错误。 如果我们没有使用任何错误,并且只想将其用于识别目的,我们也可以使用表格 -
err = try do
1 + "Hello"
rescue
RuntimeError -> "You've got a runtime error!"
ArithmeticError -> "You've got a Argument error!"
end
IO.puts(err)
在程序上运行时,会产生以下结果 -
You've got a Argument error!
NOTE - Elixir标准库中的大多数函数都实现了两次,一次返回元组,另一次引发错误。 例如,File.read和File.read! 功能。 如果文件被成功读取,则第一个返回元组,如果遇到错误,则使用此元组给出错误的原因。 如果遇到错误,第二个引发错误。
如果我们使用第一个函数方法,那么我们需要使用case匹配错误的模式并根据它采取行动。 在第二种情况下,我们使用try rescue方法来处理容易出错的代码并相应地处理错误。
Throws
在Elixir中,可以抛出一个值,然后被捕获。 Throw和Catch保留用于无法检索值的情况,除非使用throw和catch。
除了与库连接外,实例在实践中非常罕见。 例如,现在让我们假设Enum模块没有提供任何用于查找值的API,我们需要在数字列表中找到13的第一个倍数 -
val = try do
Enum.each 20..100, fn(x) ->
if rem(x, 13) == 0, do: throw(x)
end
"Got nothing"
catch
x -> "Got #{x}"
end
IO.puts(val)
运行上述程序时,会产生以下结果 -
Got 26
退出 (Exit)
当一个进程死于“自然原因”(例如,未处理的异常)时,它会发送一个退出信号。 过程也可以通过显式发送退出信号而死亡。 让我们考虑以下示例 -
spawn_link fn -> exit(1) end
在上面的示例中,链接进程通过发送值为1的退出信号而死亡。请注意,退出也可以使用try/catch“捕获”。 例如 -
val = try do
exit "I am exiting"
catch
:exit, _ -> "not really"
end
IO.puts(val)
运行上述程序时,会产生以下结果 -
not really
After
有时需要确保在某些可能引发错误的操作之后清理资源。 try/after结构允许您这样做。 例如,我们可以打开一个文件并使用after子句来关闭它 - 即使出现问题。
{:ok, file} = File.open "sample", [:utf8, :write]
try do
IO.write file, "olá"
raise "oops, something went wrong"
after
File.close(file)
end
当我们运行这个程序时,它会给我们一个错误。 但是after语句将确保在任何此类事件时关闭文件描述符。