抽出子オブジェクトはunapplyメソッドを持つオブジェクトです。
applyメソッドが引数を取り、オブジェクトを作るコンストラクタであるように、unapplyは1つのオブジェクトを受け取り、引数を返そうとします。
これはパターンマッチングと部分関数で最も頻繁に使われます。
import scala.util.Random
object CustomerID {
def apply(name: String) = s"$name--${Random.nextLong()}"
def unapply(customerID: String): Option[String] = {
val stringArray: Array[String] = customerID.split("--")
if (stringArray.tail.nonEmpty) Some(stringArray.head) else None
}
}
val customer1ID = CustomerID("Sukyoung") // Sukyoung--23098234908
customer1ID match {
case CustomerID(name) => println(name) // prints Sukyoung
case _ => println("Could not extract a CustomerID")
}
applyメソッドはnameからCustomerID文字列を作ります。unapplyは逆にnameを返します。
CustomerID("Sukyoung")は、CustomerID.apply("Sukyoung")を短く書く構文です。
case CustomerID(name) => println(name)では、unapplyメソッドを呼んでいます。
値を定義する文で、パターン中に新しい変数を使うことができるので、抽出子は変数を初期化するのに使えます。この場合unapplyメソッドが初期値を与えます。
val customer2ID = CustomerID("Nico")
val CustomerID(name) = customer2ID
println(name) // prints Nico
これは val name = CustomerID.unapply(customer2ID).getと同じです。
val CustomerID(name2) = "--asdfasdfasdf"
もし一致しない場合scala.MatchErrorが投げられます。
val CustomerID(name3) = "-asdfasdfasdf"
unapplyの戻り値型は以下のように選ばれなければなりません。
- ただのテストであれば、
Booleanを返します。例えばcase even()。 - T型のサブバリュー1つを返すのであれば、
Option[T]を返します。 - いくつかのサブバリュー
T1,...,Tnを返したいのであれば、オプショナルタプルOption[(T1,...,Tn)]でグループ化します。
時々、抽出する値の数が確定せず、入力に応じて任意の数の値を返したいことがあります。
この場合は、Option[Seq[T]]を返すunapplySeqメソッドを持つ抽出子を定義することができます。
これらのパターンと同様の例として以下のものがあります。
case List(x, y, z) =>を使ってListを分解する例やcase r(name, remainingFields @ _*) =>.のように正規表現Regexを使ってStringを分解する例です。