📜  Elixir-错误处理

📅  最后修改于: 2020-11-04 05:34:48             🧑  作者: Mango


Elixir具有三种错误机制:错误,抛出和退出。让我们详细探讨每种机制。

错误

当代码中发生异常情况时,将使用错误(或异常)。可以通过尝试将数字添加到字符串来检索示例错误-

IO.puts(1 + "Hello")

当上述程序运行时,会产生以下错误-

** (ArithmeticError) bad argument in arithmetic expression
   :erlang.+(1, "Hello")

这是一个示例内置错误。

引发错误

我们可以使用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!

– Elixir标准库中的大多数函数实现两次,一次返回元组,另一次则引发错误。例如, File.readFile.read!功能。如果成功读取文件,并且遇到错误,则第一个返回一个元组,该元组用于提供错误原因。如果遇到错误,第二个错误将引发错误。

如果我们使用第一个函数方法,那么我们需要使用用例来对错误进行模式匹配,并据此采取措施。在第二种情况下,我们对容易出错的代码使用try try方法,并相应地处理错误。

投掷

在Elixir中,可以引发一个值,以后再捕获它。 Throw和Catch保留用于除非使用throw and 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

出口

当进程死于“自然原因”(例如,未处理的异常)时,它将发送退出信号。通过显式发送退出信号,进程也可以终止。让我们考虑以下示例-

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

有时有必要确保在执行可能会引发错误的操作后清理资源。 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语句将确保在任何此类事件时文件描述符都被关闭。