为啥需要 Elixir 捕获运算符来将函数绑定到值

Posted

技术标签:

【中文标题】为啥需要 Elixir 捕获运算符来将函数绑定到值【英文标题】:Why Is The Elixir Capture Operator Needed To Bind A Function To A Value为什么需要 Elixir 捕获运算符来将函数绑定到值 【发布时间】:2016-05-28 06:42:16 【问题描述】:

我有以下灵药代码sn-p:

defmodule Rectangle do

    def area(a, b) do
        a * b
    end

    def area(a) do
        a * a
    end

end

然后我将文件加载到 iex 会话中,如下所示:

iex(1)> import_file "rectangle.exs"
:module, Rectangle,
 <<70, 79, 82, 49, 0, 0, 5, 84, 66, 69, 65, 77, 69, 120, 68, 99, 0, 0, 0, 204, 131, 104, 2, 100, 0, 14, 101, 108, 105, 120, 105, 114, 95, 100, 111, 99, 115, 95, 118, 49, 108, 0, 0, 0, 4, 104, 2, ...>>,
 :area, 1

效果如我所愿

iex(2)> Rectangle.area(9)
81

现在我想将具有 arity 1 的区域函数分配给匿名函数,例如:

iex(3)> fun = Rectangle.area/1
** (UndefinedFunctionError) undefined function Rectangle.area/0
    Rectangle.area()

但是当我输入类似:

iex(3)> fun = &Rectangle.area/1
&Rectangle.area/1

然后就可以了。虽然 Rectangle.area 已经是函数了,但是为什么elixir 函数名前面要加 &?

【问题讨论】:

这是一个公正的语法问题 - 它有点像解释器说“指向函数的指针”不是代数表达式(例如格式错误的除以 1)。请记住,Elixir 正在做“杂技”以保持与 Erlang 的兼容性 - 所以必须做出一些妥协 - 我认为。 @GavinBrelstaff 这实际上有两个原因。第一个是因为在 Elixir 语法中,parens 是可选的,引用一个函数只会调用它,除非你使用 &amp; 来表示命名函数和 arity(它需要的参数数量)。第二个原因是 Elixir 没有做任何杂技来保持与 Erlang 的兼容性,它只是假设了 Erlang 的所有语义。在 Beam VM 中,函数由名称和数量来标识。同名有 2 个 arities 实际上是 2 个不同的函数。 感谢 asonge - 我也是来学习的!仍然 IMO 允许括号在任何地方都是可选的,这对我们的用户来说非常棒,但对于维护语言的人来说,无论是否“杂技”都具有挑战性。 关于不同种类的功能很好的解释可以看这个answer 【参考方案1】:

这是因为这就是编译器解析anonymous function 的方式。

Rectangle.area/1 将被解析为 Rectangle.area1 的划分(因此出现 undefined function Rectangle.area/0 错误)。

您可以使用quote查看表达式是如何解析的:

iex> quote do &Rectangle.area/1 end
iex> quote do Rectangle.area/1 end

【讨论】:

除法与功能的关系是什么意思? @zero_coding,这就是arity - erlangcentral.org/wiki/index.php?title=Arity @zero_coding,除法不适用于函数,而是函数返回的值。在 Elixir 中(就像在 Ruby 中一样),括号对于无参数函数是可选的:Rectangle.areaRectangle.area() 相同。所以编译器试图在Rectangle 中找到一个没有参数的函数area 并应用它。另一种形式 &amp;Rectangle.area/1 告诉编译器搜索带有一个参数或 arity 1 的函数 Rectangle.area,正如 @arathunku 指出的那样。

以上是关于为啥需要 Elixir 捕获运算符来将函数绑定到值的主要内容,如果未能解决你的问题,请参考以下文章

“pin”操作符是干啥用的,Elixir 变量是可变的吗?

为啥元组在 Elixir 中不可枚举?

SQLAlchemy:自动将列名映射到值

Elixir:根据索引从列表中选择多个元素

如何通过在 Elixir 中调用进程来捕获或挽救被调用进程的崩溃错误

低代码中的短路运算符