codecamp

Elixir 错误

错误(或 异常 )用于代码中发生异常时.当试图将一个数字与原子相加,就可得到一个错误的例子:

iex> :foo + 1
** (ArithmeticError) bad argument in arithmetic expression
     :erlang.+(:foo, 1)

一个运行时错误可有​raise/1​引发:

iex> raise "oops"
** (RuntimeError) oops

其它错误可以由​raise/2​引发,通过传送错误名称和一个关键词列表作为参数:

iex> raise ArgumentError, message: "invalid argument foo"
** (ArgumentError) invalid argument foo

你也可以通过在一个模块中使用​defexception​结构来定义你自己的错误;这时你创造了一个与模块同名的错误.最常用的场景是定义一个带信息场的异常:

iex> defmodule MyError do
iex>   defexception message: "default message"
iex> end
iex> raise MyError
** (MyError) default message
iex> raise MyError, message: "custom message"
** (MyError) custom message

错误可以被解救,通过try/rescue结构:

iex> try do
...>   raise "oops"
...> rescue
...>   e in RuntimeError -> e
...> end
%RuntimeError{message: "oops"}

上述例子将运行时错误解救,并返回错误本身,然后将其打印到​iex​中.

如果错误对你毫无用处,你可以不显示它:

iex> try do
...>   raise "oops"
...> rescue
...>   RuntimeError -> "Error!"
...> end
"Error!"

实际中,Elixir开发者很少用到try/rescue结构.例如,当文件无法被打开时,许多语言会强制你解救这个错误.作为替代,Elixir中提供了File.read/1函数,其会返回一个包含文件是否被成功打开的信息的元组.

iex> File.read "hello"
{:error, :enoent}
iex> File.write "hello", "world"
:ok
iex> File.read "hello"
{:ok, "world"}

这里没有try/rescue.如果你想要处理打开文件时的不同输出,你可以简单地使用case来进行模式匹配:

iex> case File.read "hello" do
...>   {:ok, body}      -> IO.puts "Success: #{body}"
...>   {:error, reason} -> IO.puts "Error: #{reason}"
...> end

最终,打开文件时发生的错误是否为异常将由你的应用来决定.这就是Elixir为何不给File.read/1和其它许多函数强加异常.而是留给开发者来选择最好的处理方式.

当你确信一个文件存在(缺失文件确实是错误的),你可以简单地使用File.read!/1:

iex> File.read! "unknown"
** (File.Error) could not read file unknown: no such file or directory
    (elixir) lib/file.ex:305: File.read!/1

标准库中的许多函数遵循对应的异常引发模式,而非返回匹配元组.函数foo会返回{:ok, result}{:error, reason}元组,而另一个函数(foo!,同名但带有!)虽然接受与foo同样的参数,但遇到错误时会抛出异常.如果一切正常,foo!会返回(没有被元组包裹的)结果.File模块就是很好的例子.

在Elixir中,我们避免使用try/rescue,因为我们不在控制流中使用错误.我们这样解释错误:它们是预留给意料外或异常的情形的.当你需要使用控制流结构时,应该使用抛出.下面我们将讲到.


Elixir 自定义印记
Elixir 抛出
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

Elixir 基本操作符

Elixir 二进制,字符串和字符列表

Elixir 类型规格与行为

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }