- 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 - Behave
- 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
我们使用模式匹配处理了救援语句中的错误。如果我们对错误没有任何用途,只是想将其用于识别目的,我们也可以使用以下形式 -
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 来模式匹配错误并据此采取行动。在第二种情况下,我们对容易出错的代码使用尝试救援方法并相应地处理错误。
投掷
在 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 的退出信号而终止。请注意,退出也可以使用 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语句将确保文件描述符在发生任何此类事件时关闭。