Elixir:使用 & 运算符从命名函数中获取匿名函数有什么好处
Elixir: Is there any benefit of using & operator to get an anonymous function out of a named function
所以我在读这本书,在某些时候它说:
There’s a second form of the & function capture operator. You can give
it the name and arity (number of parameters) of an existing function,
and it will return an anonymous function that calls it.
但我不明白为什么有人要这样做。如果你知道你可以将命名和未命名函数绑定到变量,那么你可以从中得到什么好处。
像
这样的简单函数是很常见的
Enum.map(list, fn(element) -> element.id end)
或者只是
Enum.map(list, &(&1.id))
经过一些练习,第二个比第一个更容易阅读
关于你的问题,你也可以用同样的方式调用具名函数
Enum.map(list, &Integer.to_string/1)
替代方法是使用 fn
将函数传递给枚举
Enum.map(list, fn(number) -> Integer.to_string(number) end)
此外,捕获的变体更易于阅读。
这本书不正确。 &MyModule.my_function/0
而不是 return "an anonymous function that calls the given function" - 它 return 是一个引用命名函数的函数对象。要获得匿名函数,您可以使用 fn -> MyModule.my_function() end
.
当您在运行时重新加载模块时,这一点变得很重要:匿名函数是创建它的模块的一部分,并且由于虚拟机中只保留给定模块的两个版本("current"和 "old" 版本),你最终可能会得到一个无法再调用的函数。
让我们从这个模块开始:
defmodule MyModule do
def the_real_function() do
2
end
def anonymous_function() do
fn -> __MODULE__.the_real_function() end
end
def named_function() do
&__MODULE__.the_real_function/0
end
end
它包含我们真正感兴趣的函数,以及两个函数 return 引用真实函数的函数 - 一个带有匿名函数,一个带有命名函数对象。
让我们加载模块,获取两个函数对象,并检查我们是否可以调用它们:
iex(1)> c "my_module.ex"
[MyModule]
iex(2)> f_anon = MyModule.anonymous_function()
#Function<0.62651516/0 in MyModule.anonymous_function/0>
iex(3)> f_named = MyModule.named_function()
&MyModule.the_real_function/0
iex(4)> f_anon.()
2
iex(5)> f_named.()
2
到目前为止一切顺利。现在,假设我们需要更新模块,以便函数 returns 3 代替。我们编辑模块并重新加载它:
iex(6)> c "my_module.ex"
warning: redefining module MyModule (current version defined in memory)
my_module.ex:1
[MyModule]
iex(7)> f_anon.()
3
iex(8)> f_named.()
3
我们的函数引用仍然有效 - 很好。假设我们需要再次更新模块,到 return 4:
iex(9)> c "my_module.ex"
warning: redefining module MyModule (current version defined in memory)
my_module.ex:1
[MyModule]
iex(10)> f_anon.()
** (BadFunctionError) expected a function, got: #Function<0.62651516/0 in MyModule>
iex(10)> f_named.()
4
现在匿名功能坏了!那是因为我们得到了对它的两个模块版本的引用,因此这个匿名函数的代码不再保留在 VM 中。命名函数引用仍然有效,因为它只是引用具有给定模块、名称和元数的函数。
所以我在读这本书,在某些时候它说:
There’s a second form of the & function capture operator. You can give it the name and arity (number of parameters) of an existing function, and it will return an anonymous function that calls it.
但我不明白为什么有人要这样做。如果你知道你可以将命名和未命名函数绑定到变量,那么你可以从中得到什么好处。
像
这样的简单函数是很常见的Enum.map(list, fn(element) -> element.id end)
或者只是
Enum.map(list, &(&1.id))
经过一些练习,第二个比第一个更容易阅读
关于你的问题,你也可以用同样的方式调用具名函数
Enum.map(list, &Integer.to_string/1)
替代方法是使用 fn
Enum.map(list, fn(number) -> Integer.to_string(number) end)
此外,捕获的变体更易于阅读。
这本书不正确。 &MyModule.my_function/0
而不是 return "an anonymous function that calls the given function" - 它 return 是一个引用命名函数的函数对象。要获得匿名函数,您可以使用 fn -> MyModule.my_function() end
.
当您在运行时重新加载模块时,这一点变得很重要:匿名函数是创建它的模块的一部分,并且由于虚拟机中只保留给定模块的两个版本("current"和 "old" 版本),你最终可能会得到一个无法再调用的函数。
让我们从这个模块开始:
defmodule MyModule do
def the_real_function() do
2
end
def anonymous_function() do
fn -> __MODULE__.the_real_function() end
end
def named_function() do
&__MODULE__.the_real_function/0
end
end
它包含我们真正感兴趣的函数,以及两个函数 return 引用真实函数的函数 - 一个带有匿名函数,一个带有命名函数对象。
让我们加载模块,获取两个函数对象,并检查我们是否可以调用它们:
iex(1)> c "my_module.ex"
[MyModule]
iex(2)> f_anon = MyModule.anonymous_function()
#Function<0.62651516/0 in MyModule.anonymous_function/0>
iex(3)> f_named = MyModule.named_function()
&MyModule.the_real_function/0
iex(4)> f_anon.()
2
iex(5)> f_named.()
2
到目前为止一切顺利。现在,假设我们需要更新模块,以便函数 returns 3 代替。我们编辑模块并重新加载它:
iex(6)> c "my_module.ex"
warning: redefining module MyModule (current version defined in memory)
my_module.ex:1
[MyModule]
iex(7)> f_anon.()
3
iex(8)> f_named.()
3
我们的函数引用仍然有效 - 很好。假设我们需要再次更新模块,到 return 4:
iex(9)> c "my_module.ex"
warning: redefining module MyModule (current version defined in memory)
my_module.ex:1
[MyModule]
iex(10)> f_anon.()
** (BadFunctionError) expected a function, got: #Function<0.62651516/0 in MyModule>
iex(10)> f_named.()
4
现在匿名功能坏了!那是因为我们得到了对它的两个模块版本的引用,因此这个匿名函数的代码不再保留在 VM 中。命名函数引用仍然有效,因为它只是引用具有给定模块、名称和元数的函数。