当前位置: 首页 > 文档资料 > Elixir 中文教程 >

错误处理( Errors Handling)

优质
小牛编辑
134浏览
2023-12-01

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语句将确保在任何此类事件时关闭文件描述符。