パターン・マッチング

この章で私たちは、 Elixir における = 演算子が実際にマッチ演算子である事と、それをデータ構造の中でパターンマッチに使用する為の使い方を案内します。終盤では、事前に指定された値へアクセスする為に使われるピン演算子 ^ について学びます。

マッチ演算子

私たちは、変数を定義する為に = 演算子を何度か使っています。

iex> x = 1
1
iex> x
1

Elixir では、実際のところ = 演算子は “マッチ演算子” と呼ばれます。その理由を見ていきましょう。

iex> 1 = x
1
iex> 2 = x
** (MatchError) no match of right hand side value: 1

1 = x は有効な式であることに留意してください。さらに、左辺と右辺の両方が 1 に対して等しいのでマッチしています。その一方がマッチしない時は MatchError が起こります。

変数は、それが = の左辺にある時だけ代入することができます。

iex> 1 = unknown
** (CompileError) iex:1: undefined function unknown/0

事前に定義された unknown という変数が存在しない以上、Elixir はあなたが unknown/0 という関数の呼び出しを試みているものと考えますが、そのような関数は存在していません。

パターン・マッチ

マッチ演算子は単純にマッチングする為だけのものではなく、より複雑なデータ型を解体する為にも便利なものです。例えば、タプルでパターンマッチを使えます。

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

一方がマッチしないのならパターンマッチは失敗します。例えば、それはタプルが違うサイズである等という時に起こります。

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

さらには異なる型を比較しようとすることでも起こります。

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

もっと面白いことに、値を指定してパターンマッチを使うこともできます。以下の例では、右辺がタプルかつその最初の要素はアトムの :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}

リストでもパターンマッチは出来ます。

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

リストはそれ自身の首尾と後尾にマッチすることもサポートしています。

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

hd/1tl/1 関数と同様に、首尾と後尾が空のリストにはマッチできません。

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

[head | tail] 形式はパターンマッチだけで使われるものではなく、リストの先頭に値を付加することにも使えます。

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

パターンマッチは、開発者がタプルやリストのようなデータ構造を解体するのを容易にしてくれます。次章で見ていくことになるものとしては、Elixir における再起処理の基礎と、マップやバイナリのようにそれを異なる型へ適用するというものもあります。

The pin operator

Variables in Elixir can be rebound:

iex> x = 1
1
iex> x = 2
2

Use the pin operator ^ when you want to pattern match against an existing variable’s value rather than rebinding the variable:

iex> x = 1
1
iex> ^x = 2
** (MatchError) no match of right hand side value: 2
iex> {y, ^x} = {2, 1}
{2, 1}
iex> y
2
iex> {y, ^x} = {2, 2}
** (MatchError) no match of right hand side value: {2, 2}

Because we have assigned the value of 1 to the variable x, this last example could also have been written as:

iex> {y, 1} = {2, 2}
** (MatchError) no match of right hand side value: {2, 2}

If a variable is mentioned more than once in a pattern, all references should bind to the same pattern:

iex> {x, x} = {1, 1}
{1, 1}
iex> {x, x} = {1, 2}
** (MatchError) no match of right hand side value: {1, 2}

In some cases, you don’t care about a particular value in a pattern. It is a common practice to bind those values to the underscore, _. For example, if only the head of the list matters to us, we can assign the tail to underscore:

iex> [h | _] = [1, 2, 3]
[1, 2, 3]
iex> h
1

The variable _ is special in that it can never be read from. Trying to read from it gives a compile error:

iex> _
** (CompileError) iex:1: invalid use of _. "_" represents a value to be ignored in a pattern and cannot be used in expressions

Although pattern matching allows us to build powerful constructs, its usage is limited. For instance, you cannot make function calls on the left side of a match. The following example is invalid:

iex> length([1, [2], 3]) = 3
** (CompileError) iex:1: cannot invoke remote function :erlang.length/1 inside match

This finishes our introduction to pattern matching. As we will see in the next chapter, pattern matching is very common in many language constructs.

Is something wrong? Edit this page on GitHub.