Elixir入門 04: パターンマッチング
Tags: elixir, webdev, tutorial, programming
Published: 2018-10-09 01:27:24

---
title: Elixir入門 04: パターンマッチング
published: true
description: Elixir公式サイトの許諾を得て「Pattern matching」の解説にもとづき、加筆補正を加えてElixirの演算子による基本的なパターンマッチングについてご説明します。
tags: #elixir, #webdev, #tutorial, #programming
---

本稿はElixir公式サイトの許諾を得て「[Pattern matching](https://elixir-lang.org/getting-started/pattern-matching.html)」の解説にもとづき、加筆補正を加えてElixirの演算子による基本的なパターンマッチングについてご説明します。

# マッチ演算子
演算子`=/2`は変数に値を代入するために用いることができます。

```elixir
iex> x = 1
1
iex> x
1
```

[`=/2`](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#=/2)のElixirにおける呼び名はマッチ演算子です。左オペランドの値が右オペランドと合致(マッチ)するかを試します。マッチすればその値が返され、しないときはエラーになるのです。左オペランドが変数の場合には、右オペランドの値が代入されます。

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

右オペランドに未定義の変数があると、その名前のアリティ0の関数を探して呼び出そうとします。そして、見つからなければエラーになるのです。

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


# 演算子によるパターンマッチング
複数のデータをもつリストやタプルにも、マッチ演算子`=`は使えます。

```elixir
iex> list = [1, 2, 3]
[1, 2, 3]
iex> [1, 2, 3] = list
[1, 2, 3]
iex> [] = list
** (MatchError) no match of right hand side value: [1, 2, 3]
```

`=`演算子でリストの各要素を変数に取り出すこともできます。ただし、リストの長さもマッチしなければなりません。

```elixir
iex> [a, b, c] = list
[1, 2, 3]
iex> a
1
iex> b
2
iex> c
3
iex> [a, b] = list
** (MatchError) no match of right hand side value: [1, 2, 3]
```

`|`演算子を用いたパターンマッチングにより、ヘッドとテイルをふたつの変数に与えることもできます。ただし、関数`hd/1`や`tl/1`と同じように、空のリストはマッチさせられません。

```elixir
iex> [head | tail] = list
[1, 2, 3]
iex> [2, 3] = tail
[2, 3]
iex> [1] = head
** (MatchError) no match of right hand side value: 1
iex> 1 = head
1
iex> [h | t] = []
** (MatchError) no match of right hand side value: []
```

`|`演算子は、別のリストを後につなげるために用いることもできます。

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

タプルの要素も、マッチ演算子`=`で取り出せます。もちろん、要素の数はマッチしなければなりません。

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

両オペランドの型が異なると、マッチせずにエラーになります。

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

左オペランドの要素の一部に値を与えることもできます。すると、その要素の値もマッチしなければならないのです。

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


# ピン演算子
`=`演算子の左オペランドが変数の場合、右オペランドの値が代入されます。けれど、左オペランドの変数にピン演算子[`^/1`](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#%5E/1)を添えると、右オペランドとのマッチが求められるのです。

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

`^/1`演算子はタプルにも使えます。左オペランドの`^/1`がついた変数は今もっている値に固定され、右オペランドの対応する要素がマッチしなければならなくなるのです。

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

`=`演算子の左オペランドのパターンに同じ変数が複数ある場合、それらはすべて同じパターンを参照します。そのため、同じ変数に異なる値は代入できません。けれど、同じ変数がふたつのとき、ひとつに`^/1`演算子を添えれば、パターンとして参照されるのは今の値です。したがって、`^/1`をつけた変数に対応する右オペランドの要素がその値とマッチすれば、もうひとつの変数に別の値を与えられます。

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

パターンの中の変数で値を問わない場合があるでしょう。そのときに用いるのがアンダースコア(`_`)です。

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

`_`は特別な変数です。値を取り出すことはできず、エラーになります。

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

#### Elixir入門もくじ
- [Elixir入門 01: コードを書いて試してみる](https://dev.to/gumi/elixir-01--2585)
- [Elixir入門 02: 型の基本](https://dev.to/gumi/elixir-02--30n1)
- [Elixir入門 03: 演算子の基本](https://dev.to/gumi/elixir-03--33im)
- Elixir入門 04: パターンマッチング
- [Elixir入門 05: 条件 - case/cond/if](https://dev.to/gumi/elixir-05----casecondif-60o)
- [Elixir入門 06: バイナリと文字列および文字リスト](https://dev.to/gumi/elixir-06--35na)
- [Elixir入門 07: キーワードリストとマップ](https://dev.to/gumi/elixir-07--39hi)
- [Elixir入門 08: モジュールと関数](https://dev.to/gumi/elixir-08--1c4c)
- [Elixir入門 09: 再帰](https://dev.to/gumi/elixir-09--1a0p)
- [Elixir入門 10: EnumとStream](https://dev.to/gumi/elixir-10-enumstream-4fpb)
- [Elixir入門 11: プロセス](https://dev.to/gumi/elixir-11--2mia)
- [Elixir入門 12: 入出力とファイルシステム](https://dev.to/gumi/elixir-12--4og6)
- [Elixir入門 13: aliasとrequireおよびimport](https://dev.to/gumi/elixir-13-aliasrequireimport-55c1)
- [Elixir入門 14: モジュールの属性](https://dev.to/gumi/elixir-14--3511)
- [Elixir入門 15: 構造体](https://dev.to/gumi/elixir-15--4f43)
- [Elixir入門 16: プロトコル](https://dev.to/gumi/elixir-16--lif)
- [Elixir入門 17: 内包表記](https://dev.to/gumi/elixir-17--5gci)
- [Elixir入門 18: シギル](https://dev.to/gumi/elixir-18--5791)
- [Elixir入門 19: tryとcatchおよびrescue](https://dev.to/gumi/elixir-19-trycatchrescue-50i8)
- [Elixir入門 20: 型の仕様とビヘイビア](https://dev.to/gumi/elixir-20--j50)
- [Elixir入門 21: デバッグ](https://dev.to/gumi/elixir-21--21a1)
- [Elixir入門 22: Erlangライブラリ](https://dev.to/gumi/elixir-22-erlang-2492)
- [Elixir入門 23: つぎのステップ](https://dev.to/gumi/elixir-23--50ik)

##### 番外
- [Elixir入門: Plugを使うには](https://dev.to/gumi/elixir-plug-40lb)