Étude 3-1: 模式匹配
在area
函数中使用原子
和模式匹配
来计算一个矩形
, 三角形
和椭圆形
的面积. 如果你的参数为shape
, a
, b
:
面积公式为:
TYPE | FORMULA | DESCRIPTION |
---|---|---|
:rectange |
a * b |
矩形 |
:triangle |
a * b / 2.0 |
三角形 |
:ellipse |
:math.pi() * a * b |
椭圆形 |
实现代码:
defmodule Geom do
@moduledoc """
Functions for calculating areas of geometric shapes.
from *Études for Elixir*, O'Reilly Media, Inc., 2013.
Copyright 2013 by J. David Eisenberg.
"""
@vsn 0.1
@doc """
Calculates the area of a shape, given the shape and two of the
dimensions. Returns the product of its arguments for a rectangle,
one half the product of the arguments for a triangle, and
:math.pi times the product of the arguments for an ellipse.
"""
@spec area(atom(), number(), number()) :: number()
def area(:rectangle, length, width) do
length * width
end
def area(:triangle, base, height) do
base * height / 2.0
end
def area(:ellipse, a, b) do
:math.pi * a * b
end
end
Étude 3-2: Guards
在函数匹配的情况下, 再加上一些限制的匹配条件. 多用于限制参数的类型, 值的取值范围
参考了一些资料, 多译为保护式
, 多用于限制取值范围
避免取到无效的值, 比如数学中除数为0
是无意义的. 因此需要限制除数大于0
下面以area/3
为例子来说明如何使用保护式
defmodule Geom do
@spec area(atom(), number(), number()) :: number()
def area(:rectangle, length, width) when length >= 0 and width >= 0 do
length * width
end
def area(:triangle, base, height) when base >= 0 and height >= 0 do
base * height / 2.0
end
def area(:ellipse, a, b) when a >= 0 and b >= 0 do
:math.pi * a * b
end
end
例如area(:rectangle, length, width)
矩形面积函数分句, 除了传递三个必须的参数意外, 当length > 0
并且width >= 0
, 才会匹配到这个分句, 否则匹配不到任何area
函数, 这时候Erlang VM会刨除无法匹配的错误, 如下:
iex(60)> Geom.area(:rectangle, -1, 10)
** (FunctionClauseError) no function clause matching in Geom.area/3
iex:61: Geom.area(:rectangle, -1, 10)
要处理这类无法匹配的错误, 请看Étude 3-3
.
Étude 3-3: 下划线
defmodule Geom do
@spec area(atom(), number(), number()) :: number()
def area(:rectangle, length, width) when length >= 0 and width >= 0 do
length * width
end
def area(:triangle, base, height) when base >= 0 and height >= 0 do
base * height / 2.0
end
def area(:ellipse, a, b) when a >= 0 and b >= 0 do
:math.pi * a * b
end
def area(_, _, _) do
0
end
end
这里我们增加了第四个函数用于匹配其他非:rectangle
,:triangle
,:ellipse
形状的默认调用返回0
.
Étude 3-4: 把元组作为参数
defmodule Geom do
@spec area({atom(), number(), number()}) :: number()
# 把元组作为参数
def area({shape, dim1, dim2}) do
area(shape, dim1, dim2)
end
# Individual functions to handle each shape
@spec area(atom(), number(), number()) :: number()
defp area(:rectangle, length, width) when length >= 0 and width >= 0 do
length * width
end
defp area(:triangle, base, height) when base >= 0 and height >= 0 do
base * height / 2.0
end
defp area(:ellipse, a, b) when a >= 0 and b >= 0 do
:math.pi * a * b
end
defp area(_, _, _) do
0
end
end