LoginSignup
87
85

More than 5 years have passed since last update.

Scalaのパターンマッチ

Posted at

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"
87
85
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
87
85