In following code, the map key can be used directly or when stored in a val
, but not when stored in a case class
:
sealed trait FooKey
case object KeyA extends FooKey
case object KeyB extends FooKey
case class KaseKey(key:FooKey)
object Main extends App {
val m = Map(KeyA -> "A", KeyB -> "B")
val kk = KaseKey(KeyA)
val kv = KeyA
m(KeyA) // works
m(kv) // works
m(kk.key) // error: found: Main.kk.key.type (with underlying type FooKey)
}
The full error shown for the last line is:
Error:(16, 8) type mismatch;
found : Main.kk.key.type (with underlying type FooKey)
required: Product with Serializable with FooKey
What is the reason for this? Why is the key no longer accepted and fails a type check once stored in a case class
?
This is because of the key's type inferred by the following line:
val m = Map(KeyA -> "A", KeyB -> "B")
If you look at the REPL, it will tell you that it sees Map[Product with Serializable with FooKey,String]
. This is because the common super-type of KeyA
and KeyB
is just that. Case classes give you the Product
trait that allows iteration over the product elements, defines equals
and hashCode
.
So you should annotate your map:
val m = Map[FooKey, String](KeyA -> "A", KeyB -> "B")
Alternatively you define
sealed trait FooKey extends Product with Serializable
As explained in the answer by 0__ , this is because as a result of using case objects
for the map keys the type of m
is inferred not as FooKey
, but as Product with Serializable with FooKey
.
One could avoid this by using plain objects
instead of case objects
:
sealed trait FooKey
object KeyA extends FooKey
object KeyB extends FooKey
One possible drawback is a default Java Object hashCode is used, which may be less reasonable than the one provided by the case objects
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.