Pattern matching in Elixir can be useful to not only match values, but destructuring data. This is useful in several cases against maps and structs (also maps 🤪), for example:
1. Getting the struct type
iex> %struct{} = URI.parse("google.com") iex> struct URI
2. Matching the struct type dynamically
iex> type = URI iex> %^type{} = %URI{} %URI{} iex> %^type{} = %User{} ** (MatchError) no match of right hand side value: %User{}
3. Ensuring an object is a struct
iex> %_{} = %URI{} %URI{} iex> %_{} = %{} ** (MatchError) no match of right hand side value: %{}
4. Ensuring the map has specific keys
iex> map = %{first_name: "Vinicius", last_name: "Brasil", city: "Curitiba"} iex> %{first_name: _, last_name: _} = map %{first_name: "Vinicius", last_name: "Brasil", city: "Curitiba"} iex> %{age: _} = map ** (MatchError) no match of right hand side value: %{city: "Curitiba", first_name: "Vinicius", last_name: "Brasil"}
5. Ensuring a map is not empty
This one is tricky because %{} matches against any map value, empty or not. For instance:
iex> empty_map = %{} iex> filled_map = %{age: 21} iex> %{} = empty_map %{} iex> %{} = filled_map %{age: 21}
To ensure a map actually has keys in a guard clause, you can use Kernel.map_size/1 as the example below:
iex> defmodule Empty do ...> def is_nil_or_empty?(nil), do: true ...> def is_nil_or_empty?(map) when map_size(map) == 0, do: true ...> def is_nil_or_empty?(%{}), do: false ...> end iex> Empty.is_nil_or_empty?(nil) true iex> Empty.is_nil_or_empty?(%{}) true iex> Empty.is_nil_or_empty?(%{a: 1}) false