Pattern matching on dynamic struct types
Pattern matching is great.
Strictly speaking, I could end this post right here, but occasionally I have an interesting Elixir feature on hand. That is related to pattern matching. That is, I bet, not widely known at all.
One can pattern match on dynamic struct type with pin operator
Kernel.SpecialForms.^/1
.
It’s documentation says:
Accesses an already bound variable in match clauses. Also known as the pin operator.
Not quite expressive, neither informative. But while a documentation walks, the code talks. Check this:
iex|1 ▶ defmodule MyMod, do: defstruct ~w|foo bar|a
iex|2 ▶ mod_ok = MyMod
iex|3 ▶ mod_ko = Integer
iex|4 ▶ %^mod_ok{} = %MyMod{foo: 42, bar: 3.14}
#⇒ %MyMod{bar: 3.14, foo: 42}
iex|5 ▶ %^mod_ko{} = %MyMod{foo: 42, bar: 3.14}
#⇒ ** (MatchError) no match of right hand side value:
# %MyMod{bar: 3.14, foo: 42}
Wow. We can explicitly pattern match on dynamic struct types! It also works
in case
clauses:
iex|6 ▶ case %MyMod{foo: 42, bar: 3.14} do
...|6 ▶ %^mod_ok{} = %{foo: _foo} ->
...|6 ▶ IO.inspect(mod_ok, label: "Pinned module")
...|6 ▶ end
#⇒ Pinned module: MyMod
FWIW, the latter might be used without a pin oerator to get the struct type
iex|7 ▶ case %MyMod{foo: 42, bar: 3.14} do
...|7 ▶ %mod{} -> IO.inspect(mod, label: "Matched module")
...|7 ▶ end
#⇒ Matched module: MyMod
This match is the cumbersome spelling of %MyMod{foo: 42, bar: 3.14}.__struct__
,
though.
Permalink to the Elixir codebase: MapTest.exs.