unapply(a: T): Option[U]
を実装したオブジェクトを抽出子と呼ぶ。
基本的にコンストラクタパターンにおけるパターンマッチはケースクラスに対して行うものであるが、抽出子を実装することで、ケースクラスでないオブジェクト(上記の例では数値)に対してもパターンマッチを適用することができる。
下記は1~100までの中で平方数を探すプログラムである。
import scala.math.sqrt object Square { def apply(num: Int) = num * num def unapply(num: Int): Option[Int] = { if (sqrt(num) % 1 == 0) Some(sqrt(num).toInt) else None } } for (i <- 1 to 100) i match { case Square(x) => println(s"$i is a square number of $x.") case _ => println(s"$i is not a square number.") }
返す値の数が可変長になる場合を考慮して、unapplySeq(a: T): Option[Seq[U]]
というものも用意されている。
下記はタプル2から公約数を求めるプログラムである。
import scala.math._ object CommonDivisor { def unapplySeq(num: (Int, Int)): Option[Seq[Int]] = { val gcd = grand(num._1, num._2) if (gcd == 1) { Some(Seq(1)) } else { val divisorsOfGcd = for { i <- 1 to ceil(sqrt(gcd)).toInt if gcd % i == 0 } yield { if (i > 1 && i < sqrt(gcd)) Seq(i, gcd / i) else Seq(i) } Some(divisorsOfGcd.flatten.sorted :+ gcd) } } private def grand(a: Int, b: Int): Int = { val (higher, lower) = (max(a, b), min(a, b)) if (lower == 0) higher else grand(lower, higher % lower) } } (120, 80) match { case n @ CommonDivisor(m @ _*) => println(s"All common divisors of $n are ${m.mkString(", ")}.") } // ⇒ "All common divisors of (120,80) are 1, 2, 4, 5, 8, 10, 20, 40."