Elixir:如何处理未在最后的默认参数?

Tsu*_*omu 6 elixir

当我运行以下 Elixir 脚本时,它会打印出{"K", "Y", "L"}.

defmodule MyMod do
  def make_tuple(a \\ "X", b \\ "Y", c) do
    {a, b, c}
  end
end

IO.inspect(MyMod.make_tuple("K", "L"))
Run Code Online (Sandbox Code Playgroud)

为什么不输出{"X", "K", "L"}?这种行为背后的机制是什么?

Eve*_*ett 7

你是对的:Elixir 使用提供的任何“多余”参数来覆盖函数的部分或全部参数的默认值,从左到右填充。我对此的理解来自 Dave Thomas 的 Programming Elixir 1.6 一书。

诀窍是对于带有默认参数的函数,编译器实际上会生成多个函数。一个函数定义如下:

defmodule Example do 
  def func(p1, p2 \\ 2, p3 \\ 3, p4) do 
    IO.inspect [p1, p2, p3, p4]
  end 
end
Run Code Online (Sandbox Code Playgroud)

实际上被编译成一个看起来像这样的模块:

defmodule Example do 
  def func(p1, p4) do
    func(p1, 2, 3, p4)
  end

  def func(p1, p2, p4) do
    func(p1, p2, 3, p4)
  end

  def func(p1, p2, p3, p4) do 
    IO.inspect [p1, p2, p3, p4]
  end 
end
Run Code Online (Sandbox Code Playgroud)

顺便说一句,您可以通过使用模块的“魔术”module_info/0功能来查看这一点,例如Example.module_info().

使用一些示例值调用您的函数将帮助您了解它们的解释方式,并且可能会有一些惊喜。

Example.func("a", "b")           # => ["a",2,3,"b"]

Example.func("a", "b", "c")      # => ["a","b",3,"c"]  <--- !!!

Example.func("a", "b", "c", "d") # => ["a","b","c","d"]
Run Code Online (Sandbox Code Playgroud)

使用这样的函数可能更容易看到这种行为:

def func(p1 \\ 1, p2 \\ 2) do 
  IO.inspect [p1, p2]
end 
Run Code Online (Sandbox Code Playgroud)

并且只提供 1 个参数来调用它。它将使用左侧提供的参数;仍然使用右侧的默认值:

func("a")    #  =>  ["a", 2]
Run Code Online (Sandbox Code Playgroud)

我同意当函数具有不在参数列表末尾的可选参数时,事情会变得混乱。


Paw*_*rok 4

通过稍微尝试一下,它似乎从左侧分配参数。所以在这种情况下:

defmodule MyMod do
  def make_tuple(a \\ "X", b, c \\ "Y", d) do
    {a, b, c, d}
  end
end

IO.inspect(MyMod.make_tuple(1, 2, 3))
Run Code Online (Sandbox Code Playgroud)

你会得到{1, 2, "Y", 3}——这是对所提供参数的“最左”解释。这会导致一种情况,如果您在“末尾”添加一个参数,它会改变前面的参数的含义,并且(我认为)这就是人们通常避免使用不在参数列表末尾的可选参数的原因。