opts = [timeout: 5000, retries: 3]
IO.inspect(opts)
IO.inspect(opts == [{:timeout, 5000}, {:retries, 3}])
[timeout: 5000, retries: 3]
true
A keyword list is a list of {atom, value} tuples,
with special syntax. It's how Elixir passes options.
opts = [timeout: 5000, retries: 3]
IO.inspect(opts)
IO.inspect(opts == [{:timeout, 5000}, {:retries, 3}])
[timeout: 5000, retries: 3]
true
Read values with opts[:key] or the Keyword
module.
IO.inspect(opts[:timeout])
IO.inspect(Keyword.get(opts, :verbose, false))
IO.inspect(Keyword.fetch(opts, :retries))
5000
false
{:ok, 3}
Unlike maps, keys are ordered and may repeat. The first occurrence wins on lookup.
dup = [level: :info, level: :debug]
IO.inspect(dup[:level])
IO.inspect(Keyword.get_values(dup, :level))
:info
[:info, :debug]
Keyword.put/3 replaces all existing entries for a
key; Keyword.merge/2 applies overrides.
IO.inspect(Keyword.put(dup, :level, :warn))
defaults = [timeout: 1000, retries: 1, verbose: false]
IO.inspect(Keyword.merge(defaults, opts))
[level: :warn]
[verbose: false, timeout: 5000, retries: 3]
When a keyword list is the last argument, the
brackets are optional. That's why if and def
accept do:.
IO.inspect(String.split("a b c", " ", parts: 2))
IO.inspect(if(true, do: "yes", else: "no"))
["a", "b c"]
"yes"
Keyword.validate!/2 rejects unknown options and
fills in defaults, so typos fail loudly.
IO.inspect(Keyword.validate!([retries: 5], retries: 1, timeout: 1000))
try do
Keyword.validate!([retires: 5], retries: 1, timeout: 1000)
rescue
e in ArgumentError -> IO.puts("ArgumentError: " <> Exception.message(e))
end
[timeout: 1000, retries: 5]
ArgumentError: unknown keys [:retires] in [retires: 5], the allowed keys are: [:retries, :timeout]
Pitfall: don't pattern match on keyword lists like
[timeout: t] = opts. It only matches if the list has exactly those keys in exactly that order. UseKeyword.get/3orKeyword.validate!/2.