简体   繁体   English

从案例类中提取Map键类型为什么不起作用?

[英]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. 这是因为KeyAKeyB的常见超类型就是这样。 Case classes give you the Product trait that allows iteration over the product elements, defines equals and hashCode . 案例类为您提供了Product特质,该特质允许对product元素进行迭代,定义equalshashCode

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM