Elixir by Example

Pattern Matching

Edit any cell and run it in your browser Download source

= is the match operator. The left side is a pattern; Elixir makes it match the right side, binding variables along the way.

x = 1
IO.inspect(x)
1 = x
IO.puts("1 = x matched")
1
1 = x matched

A failed match raises MatchError.

try do
  2 = x
rescue
  e in MatchError -> IO.puts(Exception.message(e))
end
no match of right hand side value:

    1

Patterns destructure tuples, lists and maps.

{:ok, result} = {:ok, 42}
[first, second | rest] = [1, 2, 3, 4]
%{name: name} = %{name: "Ada", age: 36}
IO.inspect({result, first, second, rest, name})
{42, 1, 2, [3, 4], "Ada"}

_ matches anything and binds nothing. Prefixing a variable with _ documents what you ignore.

{_, _status, _} = {:http, 200, "OK"}
{:ok, _value} = {:ok, :ignored}

Variables can be rebound. To match against a variable's current value instead, use the pin ^.

x = 2
IO.inspect(x)

expected = :ok

case {:ok, "done"} do
  {^expected, msg} -> IO.puts("pinned match: #{msg}")
end

try do
  ^x = 3
rescue
  e in MatchError -> IO.puts(Exception.message(e))
end
2
pinned match: done
no match of right hand side value:

    3

The same variable twice in one pattern must match the same value.

{a, a} = {5, 5}
IO.inspect(a)

case {1, 2} do
  {same, same} -> IO.puts("equal")
  {_, _} -> IO.puts("different")
end
5
different

Matching works in function heads, case, with, and comprehensions. It's the main way Elixir code makes decisions.

handle = fn
  {:ok, value} -> "got #{value}"
  {:error, reason} -> "failed: #{reason}"
end

IO.puts(handle.({:ok, 1}))
IO.puts(handle.({:error, :timeout}))
got 1
failed: timeout

Pitfall: = is not assignment. {:ok, data} = File.read(path) crashes on {:error, :enoent}. That's fine when failure is a bug, but use case or with when failure is expected.

Pitfall: inside case, a bare variable in a pattern rebinds, it doesn't compare. Writing user_id -> ... matches anything. Use ^user_id.