Help us understand the problem. What is going on with this article?

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"
techno-tanoC
Elixir, Haskell, Ruby, Rustが好き
mixi
全ての人に心地よいつながりを
http://mixi.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away