#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"