I have a function which receives a map with many keys, some of them are optional. How can I write the function signature comprehending the map while allowing the optional keys to default to something?
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!
I would like it to be:
handle_my_map(%{text: "where", print_times: 3})
# (Blue): where
# (Blue): where
# (Blue): where
handle_my_map(%{text: "there"})
# (Blue): there
# (Blue): there
Something like ruby's keyword arguments:
def handle_my_map(text: nil, print_times: 2, color: 'Blue')
You can use 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
If you want to allow nils, you can use Map.merge/3
and change merge_defaults/1
to:
defp merge_defaults(map) do
Map.merge(@defaults, map, fn _key, default, val -> val || default end)
end
I would probably go with something like this:
defmodule Handler do
@defaults %{print_times: 2, color: "Blue"}
def handle_my_map(map) do
%{text: text, print_times: times, color: color} = Dict.put_new(map, @defaults)
Enum.each(1..times, fn (_) -> IO.puts ["(", color, "): ", text] end)
end
end
If you need to handle nil
values with existing keys, you can do:
defmodule Handler do
@defaults %{print_times: 2, color: "Blue"}
def handle_my_map(map) do
%{text: text, print_times: times, color: color} = @defaults
|> Dict.merge(map)
|> Enum.into %{}, fn
{key, nil} -> {key, @defaults[key]}
{key, val} -> {key, val}
end
Enum.each(1..times, fn (_) -> IO.puts ["(", color, "): ", text] end)
end
end
Well. I think you need to write another one handle_my_map
function with argument %{a: a, b: b}
. Like this:
def handle_my_map(%{a: a, b: b, optional_c: c}) do
a + b + c
end
def handle_my_map(%{a: a, b: b}) do
a + b
end
YourModule.handle_my_map %{a: 1, b: 2}
#=> 3
YourModule.handle_my_map %{a: 1, b: 2, optional_c: 3}
#=> 6
Elixir will search for a function handle_my_map
which matches your arguments until functions with arity 1 end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With