我是Elixir的新手并且坦率地说,当我们有多个具有默认值的子句时,无法理解为什么需要函数头。来自官方文档:
如果具有默认值的函数具有多个子句,则它是必需的 创建一个函数头(没有实际的主体)来声明 默认值:
defmodule Concat do def join(a, b \\ nil, sep \\ " ") def join(a, b, _sep) when is_nil(b) do a end def join(a, b, sep) do a <> sep <> b end end IO.puts Concat.join("Hello", "world") #=> Hello world IO.puts Concat.join("Hello", "world", "_") #=> Hello_world IO.puts Concat.join("Hello") #=> Hello
我读了这个,我就像“为什么?”。这取得了什么成果?这并不是两个子句不明确,编译器也无法推断出正确的调用。此外,我只是看不到添加函数头如何帮助。
我很可能忽略了一些非常简单的事情,所以我很乐意向我解释。
答案 0 :(得分:12)
Erlang函数(以及Elixir函数)由两个实体定义:name和arity。在您的示例中,def join(a, b \\ nil, sep \\ " ")
仍然是arity 3
,当编译器找到类似join("hello", "world")
的调用时,她知道它应该路由到join/3
,并传递{{1} }}作为第二个参数,并使用第三个参数的默认值。
如果我们被允许在函数体中指定默认参数,而没有这个函数头,我们最终会得到:
"world"
使编译器在调用def join(a, b \\ nil, sep), do: "default b"
def join(a, b, sep \\ nil), do: "default sep"
时卡住。
请注意,如果且只有一个或多个功能签名具有默认参数,则会要求您提供头功能。
head函数的目标是在没有默认参数值(join("hello", 42)
的情况下调用时显式定义签名。)
答案 1 :(得分:2)
您从中获得的唯一具体好处是您的默认参数将应用于所有函数调用。如果编译器允许您按照建议的方式执行,则等效项将如下所示:
def join(a, b \\ nil, _sep \\ " ") when is_nil(b) do
a
end
def join(a, b \\ nil, _sep \\ " ") do
a <> sep <> b
end
根据我的理解,它的目的只是为了减少默认情况下可能出现的混乱。