CaseClassをMapのキーとして使う場合

via 2chプログラミング言語 Scala 3冊目」

まず「caseクラス」について簡単に説明すると・・・
Scalaでは、「class」の前に「case」とつけるだけで以下の3つの特典がついてくる。

  1. インスタンスを作るときに「new」がいらなくなる。
  2. パラメータリストに「val」をつけなくても、自動的にアクセサが作られる。
  3. 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)

の様に、同じキーとして扱ってもらえる。
これは、地味に嬉しい。