为什么将第二种形式解析为 2 个参数传递给 is_number?
is_number if true, do: 1
true
is_number if true do 1 end
** (CompileError) iex:42: undefined function is_number/2
Run Code Online (Sandbox Code Playgroud)
我们可以使用引用机制来查看一个表达式在 Elixir 中是如何被解析的。
iex(6)> IO.puts Macro.to_string(quote do: (is_number if true, do: 1))
is_number(if(true) do
1
end)
:ok
iex(7)> IO.puts Macro.to_string(quote do: (is_number if true do 1 end))
is_number(if(true)) do
1
end
:ok
Run Code Online (Sandbox Code Playgroud)
因此,在您的第一种情况下, 将do被解析为 的参数if,并将整个内容传递给is_number。在第二个中, thedo具有不同的优先级并最终绑定到is_number调用本身作为第二个参数,所以我们最终调用if/1and is_number/2,这是无稽之谈。
至于为什么会这样,通常使用do将完整表达式捕获为语句,例如
if something_really_complicated arg1, arg2, arg3 do
# ...
end
Run Code Online (Sandbox Code Playgroud)
因此,在这种情况下,do尽可能松散地绑定是有意义的。相反,如果我们尝试do:使用明确的逗号作为关键字参数传递,那么它就像任何其他参数一样,因此它遵循通常的参数传递规则而不是特殊规则。
在 Elixir 这样的语言中要记住的关键是,许多在其他语言中是关键字的东西在 Elixir 中确实没有。if语句的解析方式与宏完全相同,您可以if轻松编写自己的宏,并且do:实际上只是一个关键字参数,附加了一些语法糖,而不是特定于任何特定控制语句的任何内容。这是使 Elixir(和公司)非常适合特定领域任务的重要原因。