【问题标题】:Calling an anonymous function using the pipe operator使用管道运算符调用匿名函数
【发布时间】:2018-06-07 11:08:57
【问题描述】:

我想知道为什么我们在使用管道运算符时需要添加.(),如果函数没有被调用并且只接收一个参数?

id = &(&1)

"Hello" |> id.() |> upcase # HELLO

预期:

id = &(&1)

"Hello" |> id. |> upcase # "undefined function String.upcase/0"

为什么它不起作用?我想解释一下 Elixir 的行为方式。

【问题讨论】:

  • 我意识到英语可能不是您的第一语言,但我没有关注您问题的“预期”部分。当您调用 id. 时,您期待“未定义的函数 String.upcase/0”?
  • 顺便说一句,@JoseValim 很好地解释了为什么我们有时需要括号。你可能想看看这个Q & A
  • 谢谢,@OnorioCatenacci。我只是不明白为什么id. 无效,我们需要“调用它”:id.()。我来自 JS 背景,当我们调用像 id() 这样的函数时,该函数正在执行。我希望这是有道理的。

标签: elixir


【解决方案1】:

Elixir 中没有“定义在对象上的方法”。模块具有功能。要调用函数,应将其称为String.upcase

iex> id = & &1
iex> "Hello" |> id.() |> String.upcase()
#⇒ "HELLO"

如果您坚持不使用完全限定名称的情况下调用 upcase,请预先调用 import String, only: [upcase: 1]

iex> import String, only: [upcase: 1]
iex> "Hello" |> id.() |> upcase()
#⇒ "HELLO"

匿名函数不能在管道链中使用,因为它们实际上是匿名的。将匿名函数绑定到局部变量不会使其“可管道化”,因此需要显式函数调用。与String.upcase/1 的实际调用相同,而不是“它绑定到的变量”。如果没有对 .() 的显式调用,以下内容也将无法工作:

iex> id = &String.upcase/1
iex> "hello" |> id

虽然这有效:

iex> id = &String.upcase/1
iex> "hello" |> id.()

通过检查各自的 AST 可能总能看出差异:

iex> quote do:  "hello" |> id
#⇒ {:|>, [context: Elixir, import: Kernel], ["hello", {:id, [], Elixir}]}
iex> quote do:  "hello" |> id.()
#⇒ {:|>, [context: Elixir, import: Kernel],
#   ["hello", {{:., [], [{:id, [], Elixir}]}, [], []}]}

【讨论】:

  • 谢谢。我忘记使用 quote 来获得 AST。现在更有意义了。如果我明白,我们需要使用.() 来“绑定”该函数以使其“可管道化”?
  • 我们需要使用.()来调用函数。对于命名函数ba |> b 有效,因为b 是函数名称,b ab(a) 的合法(尽管不推荐并发出警告)语法。匿名函数是anonymous,它们必须用b.(a)调用。
  • 我想我只是很困惑,少说我有[1, 2, 3] |> List.first()[1, 2, 3] |> List.first。调用List.first()应该立即执行函数并抛出错误不是吗?
  • 一点也不。两者完全相同。管道运算符始终优先,并将 LHO 作为第一个参数传递给 RHO,它必须是对函数的调用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-09
  • 1970-01-01
  • 2012-08-08
相关资源
最近更新 更多