Posted at

Scalaのパターンマッチ

More than 5 years have passed since last update.


Scalaのパターンマッチ


  • usage

  • patterns

  • pattern guard

  • tuple

  • regular expression

  • Option

  • unapply

  • case class


usage


usage.scala

val (x, y) = (1, 2)  //分解して代入 x = 1, y = 2


(x, y) match {
case (1, 2) => "one, two" //パターンで分岐
case _ => "what?"
}


patterns


patterns.scala

any match {

case 1 => //定数パターン
case _: Int => //型付きパターン
case (_, _) => //タプルパターン
case List(_, _, _) => //固定長シーケンスパターン
case List(_, _*) => //_*で任意長シーケンスパターン
case Some(x) => //コンストラクタパターン
case x => //変数パターン
case x @ (_, _) => //変数束縛パターン
case _ => //ワイルドカードパターン
}

それぞれのパターンを入れ子にすることも可能


nest.scala

nest match {

case (1, x: Int, xs @ List(_*), _) => "match!!"
case _ => "I dont know"


pattern guard

ifで条件を付けることもできる。


guard.scala

val piyo = "piyopiyo"

piyo match {
case p if p.length < 5 => "short piyo"
case p if p.length >= 5 => "long piyo" //ここにマッチ
}



tuple


tuple.scala

val p = "piyo"

val h = "hoge"

(p, h) match {
case ("piyo", "fuga") => "piyo, fuga"
case ("piyo", _) => "piyo, something" //ここにマッチする
case (_, "hoge") => "something, hoge"
case (_, _) => "something, something"
}


複数のものを一つのタプルにまとめて、条件分岐させることができる。

「片方だけが○○の時は~、両方□□の時は~」のように分岐できる。


regular expression

括弧の数でパターンが変わる。

unanchoredで部分にマッチする(束縛するのは一番最初にマッチしたもの)

入れ子も可。


regex.scala

val re1 = "piyo\d+".r

"piyo123" match {
case re1() => "match"
case _ => "mismatch"
//case re1(num)はエラー
}

val re2 = "piyo(\d+)hoge(\d+)".r
"piyo123hoge456" match {
case re2(p, h) => p + h // "123456"
case _ => "mismatch"
//case re2() はエラー
}

val re3 = "piyo(\d+)".r.unanchored
"hogepiyo123hoge" match {
case re3(num) => num // "123"
case _ => "mismatch"
}



Option

後述のcase classの一つがOption。


option.scala

val piyo: Option[String] = Some("piyo") // Option[String]で型を指定しないとSome[String]になってしまって、Noneがtype errorになる。関数の返り値の推論はOptionになるので普段は不要

piyo match {
case Some(p) => p // "piyo"
case None => "none"
}


unapply

オブジェクトにunapplyが定義されていれば、パターンマッチができる(extractor:抽出子)

BooleanかOptionを返すようにする。

コンストラクタやapplyと違う形にできる。


unapply.scala

class Piyo(val piyo: String, val hoge: String)

object Piyo {
def unapply(p: Piyo) = Some(p.piyo)
}

val piyo = new Piyo("piyopiyo", "hogehoge")
piyo match {
case Piyo(p) => p // "piyopiyo"
case _ => "not piyo..."
}



case class

case classには自動的にunapplyが定義される。

コンストラクタと同じ形のパターンになる。


caseclass.scala

case class Piyo(p: String, h: String)

val piyo = Piyo("piyo", "hoge") //applyも定義されるのでnew不要

piyo match {
case Piyo(p, h) => p + h // "piyohoge"
case _ => "mismatch"
}

//代入もできる
val Piyo(p, h) = piyo //p = "piyo", h = "hoge"