[英]Why does not Map key type work when extracted from a case class?
In following code, the map key can be used directly or when stored in a val
, but not when stored in a case class
: 在以下代码中,可以直接使用map键,也可以将其存储在
val
,但不能将其存储在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;
错误:(16,8)类型不匹配;
found : Main.kk.key.type (with underlying type FooKey)
找到:Main.kk.key.type(具有基础类型FooKey)
required: Product with Serializable with FooKey
必需:具有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
? 为什么密钥不再被接受并且一旦存储在
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]
. 如果您查看REPL,它将告诉您它看到
Map[Product with Serializable with FooKey,String]
。 This is because the common super-type of KeyA
and KeyB
is just that. 这是因为
KeyA
和KeyB
的常见超类型就是这样。 Case classes give you the Product
trait that allows iteration over the product elements, defines equals
and hashCode
. 案例类为您提供了
Product
特质,该特质允许对product元素进行迭代,定义equals
和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
. 正如0__ 的答案所解释的 ,这是因为将
case objects
用作映射键的结果是, m
的类型不是FooKey
而是Product with Serializable with FooKey
。
One could avoid this by using plain objects
instead of case objects
: 可以通过使用普通
objects
而不是case objects
来避免这种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
. 一个可能的缺点是使用了默认的Java对象hashCode ,它可能比
case objects
提供的默认值更不合理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.