Scala パターンマッチ
Scalaは強力なパターンマッチ機構を提供しており、その応用範囲も非常に広いです。
パターンマッチは一連の選択肢を含み、それぞれがキーワードから始まります。case。各選択肢には、1つのパターンと1つ以上の式が含まれます。矢印記号=>がパターンと式を区切ります。
以下は簡単な整数値パターンマッチの例です:
例
object Test {
def main(args: Array[String]) {
println(matchTest(3))
}
def matchTest(x: Int): String = x match {
case 1 => "one"
case 2 => "two"
case _ => "many"
}
}
def main(args: Array[String]) {
println(matchTest(3))
}
def matchTest(x: Int): String = x match {
case 1 => "one"
case 2 => "two"
case _ => "many"
}
}
上記のコードを実行すると、出力結果は次のようになります:
$ scalac Test.scala $ scala Test many
matchはJavaのswitchに対応しますが、セレクタ式の後に記述します。すなわち:セレクタ match { 選択肢 }。
match式は、コードに記述された順序で各パターンを試行して計算を完了します。一致するcaseが見つかると、残りのcaseはそれ以上マッチしません。
次に、異なるデータ型のパターンマッチを見てみましょう:
例
object Test {
def main(args: Array[String]) {
println(matchTest("two"))
println(matchTest("test"))
println(matchTest(1))
println(matchTest(6))
}
def matchTest(x: Any): Any = x match {
case 1 => "one"
case "two" => 2
case y: Int => "scala.Int"
case _ => "many"
}
}
def main(args: Array[String]) {
println(matchTest("two"))
println(matchTest("test"))
println(matchTest(1))
println(matchTest(6))
}
def matchTest(x: Any): Any = x match {
case 1 => "one"
case "two" => 2
case y: Int => "scala.Int"
case _ => "many"
}
}
上記のコードを実行すると、出力結果は次のようになります:
$ scalac Test.scala $ scala Test 2 many one scala.Int
この例では、最初のcaseは整数値1に対応し、2番目のcaseは文字列値twoに対応します。3番目のcaseは型パターンに対応し、渡された値が整数型かどうかを判定するために使用します。型の判定にisInstanceOfを使用するよりも、パターンマッチを使用する方が優れています。4番目のcaseはデフォルトの全一致選択肢を表し、他の一致が見つからない場合のマッチ項目で、switchのdefaultに似ています。
ケースクラスの使用
caseキーワードを使用したクラス定義がケースクラス(case classes)です。ケースクラスは特別なクラスであり、パターンマッチ用に最適化されています。
以下はケースクラスの簡単な例です:
例
object Test {
def main(args: Array[String]) {
val alice = new Person("Alice", 25)
val bob = new Person("Bob", 32)
val charlie = new Person("Charlie", 32)
for (person <- List(alice, bob, charlie)) {
person match {
case Person("Alice", 25) => println("Hi Alice!")
case Person("Bob", 32) => println("Hi Bob!")
case Person(name, age) =>
println("Age: " + age + " year, name: " + name + "?")
}
}
}
// ケースクラス
case class Person(name: String, age: Int)
}
def main(args: Array[String]) {
val alice = new Person("Alice", 25)
val bob = new Person("Bob", 32)
val charlie = new Person("Charlie", 32)
for (person <- List(alice, bob, charlie)) {
person match {
case Person("Alice", 25) => println("Hi Alice!")
case Person("Bob", 32) => println("Hi Bob!")
case Person(name, age) =>
println("Age: " + age + " year, name: " + name + "?")
}
}
}
// ケースクラス
case class Person(name: String, age: Int)
}
上記のコードを実行すると、出力結果は次のようになります:
$ scalac Test.scala $ scala Test Hi Alice! Hi Bob! Age: 32 year, name: Charlie?
ケースクラスを宣言するとき、以下の処理が自動的に行われます:
- コンストラクタの各パラメータは、明示的にvarとして宣言されない限り、すべてvalになります。ただし、これは推奨されません;
- コンパニオンオブジェクトにapplyメソッドが提供されるため、newキーワードを使用せずにオブジェクトを構築できます;
- unapplyメソッドが提供され、パターンマッチを機能させます;
- toString、equals、hashCode、copyメソッドが生成されます。ただし、これらのメソッドの定義が明示的に与えられている場合は除きます。