异常名称的模式匹配

ank*_*981 2 elixir

我正在探索Elixir,并且对此表示怀疑。假设我有这样的代码:

defmodule Drop2 do
    def fall_velocity(planemo, distance) do
        gravity = case planemo do
            :earth -> 9.8
            :moon -> 1.6
            :mars -> 3.71
        end
        :math.sqrt(2 * gravity * distance)
    end
end
Run Code Online (Sandbox Code Playgroud)

我传递一个负数distance以使函数失败:

iex(8)> Drop2.fall_velocity(:earth, -20)
** (ArithmeticError) bad argument in arithmetic expression
    (stdlib) :math.sqrt(-392.0)
             drop2.ex:9: Drop2.fall_velocity/2
Run Code Online (Sandbox Code Playgroud)

通过添加异常处理,可以使此方法更好:

defmodule Drop2 do
    def fall_velocity(planemo, distance) do
        try do
            gravity = case planemo do
                :earth -> 9.8
                :moon -> 1.6
                :mars -> 3.71
            end
            :math.sqrt(2 * gravity * distance)
        rescue
            ArithmeticError -> {:error, "Distance must be non-negative number"}
            CaseClauseError -> {:error, "Unknown planemo: #{planemo}"}
        end
    end
end
Run Code Online (Sandbox Code Playgroud)

现在我们有:

iex(9)> Drop2.fall_velocity(:earth, -20)
{:error, "Distance must be non-negative number"}
Run Code Online (Sandbox Code Playgroud)

太好了,但是我看不到模式如何ArithmeticError匹配。在前面的示例中,生成的异常主要是文本,并(ArithmeticError)用括号括起来。这不是Elixir中通常的模式匹配。这是怎么回事?

Dog*_*ert 5

在前面的示例中,生成的异常主要是文本,并在括号中包裹了(ArithmeticError)。

异常不是文本,而是正在iex打印异常的文本表示形式,而不是确切的值(source)。确切的例外是:

iex(1)> try do
...(1)>   :math.sqrt(-1)
...(1)> rescue
...(1)>   e -> e
...(1)> end
%ArithmeticError{message: "bad argument in arithmetic expression"}
Run Code Online (Sandbox Code Playgroud)

这是一个ArithmeticError带有message字段的结构,如Kernel.SpecialForms.try / 1的文档所述:

救援条款

除了依赖模式匹配外,抢救子句还为异常提供了一些便利,使人们可以通过其名称抢救异常。