Pattern matching

The match operator is not only used to match against simple values, but it is also useful for destructuring more complex data types. For example, we can pattern match on tuples:

iex> {a, b, c} = {:hello, "world", 42}
{:hello, "world", 42}
iex> a
:hello
iex> b
"world"

A pattern match will error in the case the sides can’t match. This is, for example, the case when the tuples have different sizes:

iex> {a, b, c} = {:hello, "world"}
** (MatchError) no match of right hand side value: {:hello, "world"}

And also when comparing different types:

iex> {a, b, c} = [:hello, "world", "!"]
** (MatchError) no match of right hand side value: [:hello, "world", "!"]

More interestingly, we can match on specific values. The example below asserts that the left side will only match the right side when the right side is a tuple that starts with the atom :ok:

iex> {:ok, result} = {:ok, 13}
{:ok, 13}
iex> result
13

iex> {:ok, result} = {:error, :oops}
** (MatchError) no match of right hand side value: {:error, :oops}

We can pattern match on lists:

iex> [a, b, c] = [1, 2, 3]
[1, 2, 3]
iex> a
1

A list also supports matching on its own head and tail:

iex> [head | tail] = [1, 2, 3]
[1, 2, 3]
iex> head
1
iex> tail
[2, 3]

Similar to the hd/1 and tl/1 functions, we can’t match an empty list with a head and tail pattern:

iex> [h|t] = []
** (MatchError) no match of right hand side value: []

The [head | tail] format is not only used on pattern matching but also for prepending items to a list:

iex> list = [1, 2, 3]
[1, 2, 3]
iex> [0|list]
[0, 1, 2, 3]

Pattern matching allows developers to easily destructure data types such as tuples and lists. As we will see in following chapters, it is one of the foundations of recursion in Elixir and applies to other types as well, like maps and binaries.