有没有一种方法可以定义不同参数数量的重载函数,例如在C#中我只需要这样做:
foo(bar)
或者
foo(bar, baz)
在Elixir中,唯一的方法是将它们放在单独的模块中,这很快会变得混乱。有没有其他解决办法呢?
编辑:我做出了错误的假设。我看到的重载函数示例恰好具有相同的arity,因此我(错误地)认为这是一个要求。函数根据其名称和arity唯一标识,因此您实际上可以重载具有不同arity的函数。
foo(bar)
或者
foo(bar, baz)
在Elixir中,唯一的方法是将它们放在单独的模块中,这很快会变得混乱。有没有其他解决办法呢?
编辑:我做出了错误的假设。我看到的重载函数示例恰好具有相同的arity,因此我(错误地)认为这是一个要求。函数根据其名称和arity唯一标识,因此您实际上可以重载具有不同arity的函数。
foo(bar)
和foo(bar, baz)
是完全不同的函数。但这只是一个技术细节。要在Elixir中编写“重载”函数,您可以编写以下定义:sum
:defmodule Math do
def sum(list), do: sum(list, 0)
def sum([], acc), do: acc
def sum([h|t], acc), do: sum(t, acc + h)
end
defmodule Math do
def zero?(0) do
true
end
def zero?(x) when is_number(x) do
false
end
end
Math.zero?(0) #=> true
Math.zero?(1) #=> false
Math.zero?([1,2,3])
#=> ** (FunctionClauseError)
在单个模块中,同一函数名称可以有多个重载(尽管文档中将此概念称为clauses
)。
sum([], acc)
和sum([h|t], acc)
一样。在这种情况下,函数按源代码顺序尝试,因此当您调用sum([1, 2, 3], 0)
时,它将首先尝试匹配sum([], acc)
,但由于[1, 2, 3]
不是空列表,所以会失败,然后将尝试sum([h|t], acc)
,这将成功,因为列表有一个头和一个尾。您不能有两个名称和元数相同但不匹配其参数的函数。 - bitwalkersum(list, acc), do: acc + 1
sum(list, acc), do: acc + 2
但以下内容是有效的:sum([], acc), do: acc
sum(list, acc), do: [h|t] = list; sum(t, acc + h)
原因是第一种情况无法区分两个函数子句,这是无效的。然而第二种情况可以。 - bitwalker