只是为了澄清命名,它们都是功能。一个是命名函数,另一个是匿名函数。但是您是对的,它们的工作方式有些不同,我将说明为什么它们那样工作。
让我们从第二个开始fn
。fn
是一个闭包,类似于lambda
Ruby中的。我们可以如下创建它:
x = 1
fun = fn y -> x + y end
fun.(2) #=> 3
一个函数也可以有多个子句:
x = 1
fun = fn
y when y < 0 -> x - y
y -> x + y
end
fun.(2) #=> 3
fun.(-2) #=> 3
现在,让我们尝试一些不同的东西。让我们尝试定义期望不同数量参数的不同子句:
fn
x, y -> x + y
x -> x
end
** (SyntaxError) cannot mix clauses with different arities in function definition
不好了!我们得到一个错误!我们不能混合使用期望数量不同的子句。函数始终具有固定的对偶度。
现在,让我们谈谈命名函数:
def hello(x, y) do
x + y
end
正如预期的那样,它们有一个名称,并且还可以接收一些参数。但是,它们不是闭包:
x = 1
def hello(y) do
x + y
end
该代码将无法编译,因为每次您看到时def
,都会得到一个空的变量范围。这是它们之间的重要区别。我特别喜欢这样一个事实,即每个命名函数都以干净的开头开头,并且不会让不同作用域的变量混合在一起。您有明确的界限。
我们可以检索上面作为匿名函数的命名hello函数。您自己提到了它:
other_function(&hello(&1))
然后您问,为什么我不能hello
像其他语言那样简单地通过它?这是因为Elixir中的功能是通过名称和 Arity 来标识的。因此,期望两个参数的函数与期望三个参数的函数是不同的函数,即使它们具有相同的名称。因此,如果我们只是通过了hello
,我们将不知道hello
您的实际含义。具有两个,三个或四个参数的那个?这与为什么我们不能使用带有不同Arities的子句创建匿名函数的原因完全相同。
从Elixir v0.10.1开始,我们有了一种语法来捕获命名函数:
&hello/1
这将捕获带有Arity 1的本地命名函数hello。在整个语言及其文档中,以这种hello/1
语法标识函数是很常见的。
这也是Elixir使用点来调用匿名函数的原因。由于您不能简单地hello
作为一个函数传递,而是需要显式捕获它,因此命名函数和匿名函数之间存在自然的区别,并且调用每个函数的语法不同会使所有内容都更加明确(Lispers对此很熟悉)由于Lisp 1与Lisp 2的讨论)。
总体而言,这就是我们拥有两个功能以及它们表现不同的原因。