如何将匿名函数传递给 Elixir 中的管道

Posted

技术标签:

【中文标题】如何将匿名函数传递给 Elixir 中的管道【英文标题】:How to pass an anonymous function to the pipe in Elixir 【发布时间】:2014-08-26 22:54:00 【问题描述】:

我想这样写代码:

def boundary do
  :crypto.rand_bytes(8)
  |> Base.encode16
  |> &("--------FormDataBoundary" <> &1)
end

但它不起作用。

【问题讨论】:

【参考方案1】:

它看起来有点奇怪,但必须有效:

def boundary do
  :crypto.rand_bytes(8)
  |> Base.encode16
  |> (&("--------FormDataBoundary" <> &1)).()
end

【讨论】:

它有什么理由这么奇怪吗?当我将函数传递给管道时,我将其视为变量(是的,我来自 javascript),但执行 (fn).() 看起来我正在立即调用它,但我不是。 (&amp;("--------FormDataBoundary" &lt;&gt; &amp;1)).() 看起来您定义了一个接受 1 个参数的匿名函数,然后用零参数调用它,然后它就成为了管道的一部分?我不明白你为什么最后需要.()。这不是调用匿名函数吗?我不想自己称呼它,我希望它成为管道的一部分。 我想我现在明白了。该函数是管道的一部分这一事实意味着管道提供第一个参数。剩下的就是调用函数了,你可以使用.() 一开始我很纠结。然后我意识到当你使用管道时,管道中的每个函数都是函数调用,而不是函数引用。如果您的管道中的函数具有 2+ 元数,这一点很明显,从那时起您 必须 也可以为命名函数使用括号。一旦您意识到所有命名函数也被显式调用,使用括号为匿名函数进行函数调用并不奇怪。如果它们的元数为 1,则可以省略括号(使其看起来像函数引用而不是函数调用,但它仍然是函数调用。)【参考方案2】:

相关:如果“匿名”函数已分配给变量,您可以像这样通过管道传递给它:

def boundary do
  add_marker = fn (s) ->
    "--------FormDataBoundary" <> s
  end

  :crypto.rand_bytes(8)
  |> Base.encode16
  |> add_marker.()
end

【讨论】:

【参考方案3】:

接受的答案有效,但您可以使用

更优雅地做到这一点
(&"--------FormDataBoundary#&1").()

而不是

(&("--------FormDataBoundary" <> &1)).()

这是完整的功能:

def boundary do
  :crypto.strong_rand_bytes(8)
  |> Base.encode16()
  |> (&"--------FormDataBoundary#&1").()
end

奖励:我还用:crypto.strong_rand_bytes/1 替换了:crypto.rand_bytes/1(elixir 1.6+ 中不存在)。

【讨论】:

【参考方案4】:

你也可以这样使用:

def boundary do
  :crypto.rand_bytes(8)
  |> Base.encode16
  |> (fn chars -> "--------FormDataBoundary" <> chars end).()
end

与其他形式相比,这种形式的一个优势是您可以轻松编写简单的“案例”语句:

def do_some_stuff do
  something
  |> a_named_function()
  |> (
    fn
      :ok, something -> something
      :error, something_else ->
        Logger.error "Error"
        # ...
    end
  ).()
end

发件人:

Anonymous functions in pipe chain · Elixir Recipes

使用fn 比couchemar's answer 更清晰一点

def boundary do
  :crypto.rand_bytes(8)
  |> Base.encode16
  |> (&("--------FormDataBoundary" <> &1)).()
end

...但是,对于您的特定示例,使用&amp; 的上述表单可能是最好的。如果管道表达式更复杂,命名匿名函数参数可能更有用。

我的回答也比Nathan Long's answer简洁一点

def boundary do
  add_marker = fn (s) ->
    "--------FormDataBoundary" <> s
  end

  :crypto.rand_bytes(8)
  |> Base.encode16
  |> add_marker.()
end

...如果由于某种原因您需要在管道中多次调用该函数,他的回答会更好。

【讨论】:

也可以跳过括号:|&gt; fn x -&gt; x end.()【参考方案5】:

你真的不能走吗?

thing
|> func_one()
|> fn input -> do_stuff_here() end)

你可以做一些事情,比如把东西直接放到箱子里

thing
|> func_one()
|> case do

所以,我认为您可以直接输入匿名函数。

【讨论】:

最后一行需要像|&gt; (fn input -&gt; do_stuff_here() end).(),否则你是正确的。 我不知道有人可以通过管道进入case tho - 这很方便!

以上是关于如何将匿名函数传递给 Elixir 中的管道的主要内容,如果未能解决你的问题,请参考以下文章

当使用局部变量将匿名函数传递给命名函数时,Javascript中的范围问题

node-java 是不是允许将匿名函数作为参数传递给 java?

Elixir 中的命名函数和匿名函数有啥区别?

在具有 GPU 加速的 arrayfun 中使用匿名函数 (Matlab)

的重要性 。在 Elixir 函数式编程中的匿名函数中 [重复]

调用如何将其参数传递给内部函数? [复制]