首页 > 解决方案 > 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"))

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

标签: elixir

解决方案


You are correct: Elixir uses any "excess" arguments provided to override a function's default values for some or all of its parameters, filled from left to right. My understanding of this came from the Programming Elixir 1.6 book by Dave Thomas.

The trick is that for functions with default arguments, the compiler actually generates multiple functions. A function defined like this:

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

Actually gets compiled down to a module that looks something like this:

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

By the way, you can see this by using a module's "magic" module_info/0 function, e.g. Example.module_info().

Calling your functions with some sample values will help you understand how they are interpreted, and there may be a few surprises.

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"]

It may be a bit easier to see this behavior with a function like this:

def func(p1 \\ 1, p2 \\ 2) do 
  IO.inspect [p1, p2]
end 

And calling it with only 1 argument provided. It will use the provided argument on the left side; the default on the right still gets used:

func("a")    #  =>  ["a", 2]

I agree that things do get confusing when a function has optional arguments that aren't at the end of the argument list.


推荐阅读