Scala 为什么从案例类提取时映射键类型不起作用?

Scala 为什么从案例类提取时映射键类型不起作用?,scala,dictionary,types,Scala,Dictionary,Types,在以下代码中,映射键可以直接使用,也可以存储在val中时使用,但不能存储在案例类中时使用: 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 = Ka

在以下代码中,映射键可以直接使用,也可以存储在
val
中时使用,但不能存储在
案例类中时使用:

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)
}
最后一行显示的完整错误为:

错误:(16,8)类型不匹配

找到:Main.kk.key.type(具有基础类型FooKey)

必需:可使用FooKey序列化的产品


这是什么原因?为什么密钥不再被接受,并且一旦存储在
案例类中就无法通过类型检查?

这是因为以下行推断出密钥的类型:

val m = Map(KeyA -> "A", KeyB -> "B")
如果您查看REPL,它会告诉您它看到了
Map[Product with Serializable with FooKey,String]
。这是因为
KeyA
KeyB
的常见超类型就是这样。案例类提供了
产品
特性,允许在产品元素上进行迭代,定义
等于
哈希代码

因此,您应该为地图添加注释:

val m = Map[FooKey, String](KeyA -> "A", KeyB -> "B")
或者,您可以定义

sealed trait FooKey extends Product with Serializable
如中所述,这是因为对映射键使用
case objects
的结果是
m
的类型被推断为
FooKey
,而不是
可与FooKey序列化的产品

可以通过使用普通的
对象
而不是
案例对象
来避免这种情况:

sealed trait FooKey
object KeyA extends FooKey
object KeyB extends FooKey

一个可能的缺点是使用了a,这可能不如这里的
case对象所提供的合理
val m:Map[FooKey,String]=Map(KeyA->“A”,KeyB->“B”)m(kk.key)
似乎有效。还有一种选择,我可以将其中一个键归因于从可能的键类型中删除
Product
val m=Map((KeyA:FooKey>)-“A”,KeyB->“B”)
您使用的是哪个版本的Scala?在Scala 2.11中,case类和case对象都实现了
Product
。作为一种特性,
FooKey
根据定义是抽象的,不需要实现任何东西。您是正确的。我把它误认为是一个
密封类
(它显示了与我的原始示例相同的行为)。简单地说,正确的方法是将键类型显式指定为
FooKey