带可选键的模式匹配映射

Uri*_*ssi 15 elixir

我有一个函数接收带有许多键的映射,其中一些是可选的.如何编写功能签名,理解地图,同时允许可选键默认为某些东西?

def handle_my_map(%{text: text, 
                    print_times: print_times, # this I want to default to 2
                    color: color # this I want to default to "Blue"
  }) do
  Enum.each(1..print_times, fn (_) -> IO.puts ["(", color, "): ", text] end)
end

Test.handle_my_map(%{text: "here", print_times: 5, color: "Red"})
# (Red): here
# (Red): here
# (Red): here
# (Red): here
# (Red): here

handle_my_map(%{text: "there"})
# => MatchError!
Run Code Online (Sandbox Code Playgroud)

我希望它是:

handle_my_map(%{text: "where", print_times: 3})
# (Blue): where
# (Blue): where
# (Blue): where
handle_my_map(%{text: "there"})
# (Blue): there
# (Blue): there
Run Code Online (Sandbox Code Playgroud)

像ruby的关键字参数:

def handle_my_map(text: nil, print_times: 2, color: 'Blue')
Run Code Online (Sandbox Code Playgroud)

Jos*_*lim 12

你可以使用Map.merge/2:

defmodule Handler do
  @defaults %{print_times: 2, color: "Blue"}

  def handle_my_map(map) do
    %{text: text, print_times: times, color: color} = merge_defaults(map)
    Enum.each(1..times, fn (_) -> IO.puts ["(", color, "): ", text] end)
  end

  defp merge_defaults(map) do
    Map.merge(@defaults, map)
  end
end
Run Code Online (Sandbox Code Playgroud)

如果你想允许nils,你可以使用Map.merge/3merge_defaults/1改为:

defp merge_defaults(map) do
  Map.merge(@defaults, map, fn _key, default, val -> val || default end)
end
Run Code Online (Sandbox Code Playgroud)

  • 如果所有值都是映射,您可以执行类似于此处所做的操作:https://github.com/elixir-lang/elixir/blob/master/lib/mix/lib/mix/config.ex#L192-L196如果没有,您只需要检查两个值是否都是映射,然后调用Map.merge/2. (2认同)