- Elixir 教程
- Elixir - 首页
- Elixir - 概述
- Elixir - 环境
- Elixir - 基本语法
- Elixir - 数据类型
- Elixir - 变量
- Elixir - 运算符
- Elixir - 模式匹配
- Elixir - 决策
- Elixir - 字符串
- Elixir - 字符列表
- Elixir - 列表和元组
- Elixir - 关键字列表
- Elixir - 映射
- Elixir - 模块
- Elixir - 别名
- Elixir - 函数
- Elixir - 递归
- Elixir - 循环
- Elixir - 可枚举
- Elixir - 流
- Elixir - 结构体
- Elixir - 协议
- Elixir - 文件 I/O
- Elixir - 进程
- Elixir - 符号
- Elixir - 推导式
- Elixir - 类型规范
- Elixir - 行为
- Elixir - 错误处理
- Elixir - 宏
- Elixir - 库
- Elixir 有用资源
- Elixir - 快速指南
- Elixir - 有用资源
- Elixir - 讨论
Elixir - 错误处理
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
我们在 `rescue` 语句中使用模式匹配处理了错误。如果我们没有使用错误,只是想将其用于识别目的,我们也可以使用以下形式:
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.read` 和 `File.read!` 函数。如果文件读取成功,第一个函数将返回一个元组;如果遇到错误,则使用此元组来提供错误原因。第二个函数如果遇到错误则引发错误。
如果我们使用第一种函数方法,则需要使用 `case` 来匹配错误模式并根据该模式采取行动。在第二种情况下,我们对容易出错的代码使用 `try rescue` 方法并相应地处理错误。
抛出
在 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
退出
当进程因“自然原因”(例如未处理的异常)死亡时,它会发送一个退出信号。进程也可以通过显式发送退出信号来死亡。让我们考虑以下示例:
spawn_link fn -> exit(1) end
在上面的示例中,链接的进程通过发送值为 1 的退出信号死亡。请注意,`exit` 也可以使用 `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` 语句将确保在任何此类事件发生时关闭文件描述符。