第18章：Scalaのパターンマッチ

今回は __パターンマッチ__ だ！！
こいつ凄い奴なんだぜ。

実は最初、全く使い道がわからなかった。
ifで良いんじゃね？とか思ってけど、
ifよりもやれることの幅が広すぎるんだ。

書きながら見てみよう！

# パターンマッチとは
ifやswitchのように条件分岐に分類されるのかな。
ただifやswitchと同等に使うだけではもったいない。

どれだけ凄いか見てみよう！

# パターン
意識してなかったけどパターン色々あるんだね。。。

最初は戸惑うかもしれないけど、簡単なパターンから見てみよう。

## 定数パターン
まずは、Javaのswich文ぽいやつ。

```scala:PatternMatchConst.scala
import scala.util.Random

object PatternMatchConst {

  def main(args: Array[String]): Unit = {
    val random = Random.nextBoolean

    val num = random match {
      case true => 1
      case false => 0
    }

    println("random:" + random)
    println("number:" + num)
  }

}
```

動かしてみるよ！

```
$ scalac PatternMatchConst.scala

$ scala PatternMatchConst
random:true
number:1
```

ここではランダムな`Boolean` を生成して変数`random` に束縛している。
そして変数`random` に対してパターンマッチを実施する。
それが`case` の後の`true` と`false` だ。

そしてマッチした方の値を変数`num` に束縛させる。

パターンマッチも式であることを意識するために
戻り値を返し変数に束縛させるソースコードにしてみた。


### 束縛とは
本とかだと、以下のような記述が良く出てくる。

__値を変数に束縛する__

式で得た結果を変数に紐づけるという感じなのかな。
代入と似ているけど、考え方から違うんだよね。

__bind__ の訳として用いられているね。

今回はパターンマッチが本題なので、詳しく知りたい場合は以下を読んでみて下さい。

[Smalltalk use: better《余録》代入 vs. 束縛](http://d.hatena.ne.jp/kotsubu-chan/20000701)

## 型パターン
次は __型__ だ。Javaの`instanceof`と似ている。

```scala:PatternMatchType.scala
object PatternMatchType {

  def main(args: Array[String]): Unit = {
    val list = List(1, true, "J")

    for (value <- list) {
      value match {
        case num: Integer => println("num=" + num)
        case bool: Boolean => println("bool=" + bool)
        case name: String => println("name=" + name)
        case _ => println("value=" + value)
      }
    }

  }

}
```

```
$ scalac PatternMatchType.scala

$ scala PatternMatchType
num=1
bool=true
name=J
```

型に応じてやることを決めているんだ。

## ワイルドカードパターン
つぎはワイルドカード`_`だ。

```scala:PatternMatchWild.scala
object PatternMatchWild {

  def main(args: Array[String]): Unit = {
    val num = 4

    num match {
      case _ => println("number:" + num)

    }
  }

}
```

```
$ scalac PatternMatchWild.scala

$ scala PatternMatchWild
number:4
```

全てのパターンにマッチしちゃうんだ。

### ワイルドカードパターンがない場合
どうなるか見てみよう。

```scala:PatternMatchNoWild.scala
object PatternMatchNoWild {

  def main(args: Array[String]): Unit = {
    val list = List(1, true, "J")

    for (value <- list) {
      value match {
        case num: Integer => println("num=" + num)
        case bool: Boolean => println("bool=" + bool)
      }
    }

  }

}
```

```
$ scalac PatternMatchNoWild.scala

$ scala PatternMatchNoWild
num=1
bool=true
scala.MatchError: J (of class java.lang.String)
	at PatternMatch3_2$$anonfun$main$1.apply(PatternMatch3_2.scala:7)
	at PatternMatch3_2$$anonfun$main$1.apply(PatternMatch3_2.scala:6)
	at scala.collection.immutable.List.foreach(List.scala:318)
	at PatternMatch3_2$.main(PatternMatch3_2.scala:6)
	at PatternMatch3_2.main(PatternMatch3_2.scala)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at scala.tools.nsc.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:71)
	at scala.tools.nsc.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:31)
	at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:139)
	at scala.tools.nsc.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:71)
	at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:139)
	at scala.tools.nsc.CommonRunner$class.run(ObjectRunner.scala:28)
	at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:45)
	at scala.tools.nsc.CommonRunner$class.runAndCatch(ObjectRunner.scala:35)
	at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:45)
	at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:74)
	at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96)
	at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:105)
	at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
```

こんな感じになっちゃいました。 
何かしらのパターンにマッチしないといけないんだね。 

別の手段で制御しないのであれば、ワイルドカードパターンを最後に書くようにしよう。

## 変数パターン
次は変数に束縛させてみるよ。ここからJavaの世界から離れるね。

```scala:PatternMatchVar.scala
object PatternMatchVar {

  def main(args: Array[String]): Unit = {
    val random = 4

    val result = random match {
      case num => num * 2
    }

    println("random:" + random)
    println("number:" + result)
  }

}
```

```
$ scalac PatternMatchVar.scala

$ scala PatternMatchVar
random:4
number:8
```

まずこのパターンは全ての値にマッチするんだ。
しかもマッチした値を __変数 `num` に束縛__させているんだ。

そして処理の中で使用している。  
変数`num` を2倍にしているんだ。

ワイルドカードパターンと似ているけど、別の変数に束縛していところが違うんだ。

##シーケンスパターン

なんとシーケンスともマッチングできるんだ。

```scala:PatternMatchSeq.scala
object PatternMatchSeq {

  def main(args: Array[String]): Unit = {
    val seq = Seq(1, 2, 3, 4)

    val result = seq match {
      case Seq(1, a, _*) => a
      case _ => 0
    }

    println("number:" + result)
  }

}
```

```
$ scalac PatternMatchSeq.scala

$ scala PatternMatchSeq
number:2
```

ここでは先頭要素が`1` で、要素数2個以上の`Seq` という条件でマッチングしている。
`_*` は0個以上の任意の要素を表すんだ。  
そして、1番目の要素を変数`a` に束縛しているんだ。  

## タプルパターン
タプルでももちろんできるぞ。

```scala:PatternMatchTuple.scala
object PatternMatchTuple {

  def main(args: Array[String]): Unit = {
    val tuple = (1, 2, "OK")

    val result = tuple match {
      case (1, 2, x) => x
      case _ => "NG"
    }

    println("result:" + result)
  }

}
```

```
$ scalac PatternMatchTuple.scala

$ scala PatternMatchTuple
result:OK
```

もう馴れてきたかな？


## コンストラクタパターン
ケースクラスと組み合わせて使うパターンだ。 
フィールドまでマッチングできるようになるんだ。

```scala:PatternMatchConstructor.scala
object PatternMatchConstructor {

  case class Person(name: String, age: Int, education: String)

  def main(args: Array[String]): Unit = {
    val person = Person("椿山 清美", 15, "男塾")

    val belongTo = person match {
      case Person("独眼鉄", _, "男塾") => "鎮守直廊三人衆 "
      case Person("椿山 清美", _, "男塾") => "一号生"
      case _ => "一般市民"
    }

    println("所属:" + belongTo)
  }

}
```

```
$ scalac PatternMatchConstructor.scala

$ scala PatternMatchConstructor
所属:一号生
```

フィールドまでパターンマッチ対象にしているから 
独眼鉄様にマッチしないのがわかったかな？

今回はここまでだ！

#まとめ
パターンマッチ凄い奴だろ？ 
こんな凄い奴は使わないと損だぞ。

でも最近は、パターンマッチを書かないで綺麗に書けないかな？
と考えてたりするんだよね。。。

今回も 
__体で感じてくれたかな？__