CaseClassをMapのキーとして使う場合
まず「caseクラス」について簡単に説明すると・・・
Scalaでは、「class」の前に「case」とつけるだけで以下の3つの特典がついてくる。
- インスタンスを作るときに「new」がいらなくなる。
- パラメータリストに「val」をつけなくても、自動的にアクセサが作られる。
- toString,hashCode,equalsの「自然な」実装が追加される。
ちなみに、特典1は内部的には、コンパニオンオブジェクト(同名のobject)に、apply,unapplyを定義することによって実現されている。
簡単に実験するとこんな感じ・・・
scala> case class Point(x:Int, y:Int) defined class Point scala> Point(1,2) res0: Point = Point(1,2) scala> Point(3,4) res1: Point = Point(3,4) scala> val p1 = Point(1,2) p1: Point = Point(1,2) scala> p1.x res2: Int = 1 scala> p1.y res3: Int = 2 scala> p1.hashCode res4: Int = -1589888475 scala> p1.toString res5: String = Point(1,2) scala> p1 equals res1 res6: Boolean = false scala> p1 equals res0 res7: Boolean = true
このうち、equalsの特典はMapなどのキーに使う場合などに、効果を発揮する。
通常独自に作ったクラスをMapのキーにした場合は
scala> class People(name:String) defined class People scala> new People("hoge") res8: People = People@3c56b64c scala> new People("hoge") res9: People = People@224260ab scala> Map(res8 -> "piyo", res9 -> "PIYO") res10: scala.collection.immutable.Map[People,java.lang.String] = Map(People@3c56b64c -> piyo, People@224260ab -> PIYO)
のように、同じパラメータで作った2つのインスタンスは、別のキーとして扱われる。
しかし、caseクラスにすると
scala> case class People(name:String) defined class People scala> new People("hoge") res13: People = People(hoge) scala> new People("hoge") res14: People = People(hoge) scala> Map(res13 -> "piyo", res14 -> "PIYO") res15: scala.collection.immutable.Map[People,java.lang.String] = Map(People(hoge) -> PIYO) scala> res15.get(People("hoge")) res16: Option[java.lang.String] = Some(PIYO)
の様に、同じキーとして扱ってもらえる。
これは、地味に嬉しい。