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

我想这样写代码:

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

但它不起作用。

【问题讨论】:

    标签: elixir


    【解决方案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
        

        发件人:


        使用fncouchemar'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 - 这很方便!
        猜你喜欢
        • 1970-01-01
        • 2019-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多