【问题标题】:Why does not Map key type work when extracted from a case class?为什么从案例类中提取 Map 键类型不起作用?
【发布时间】:2015-03-13 10:19:20
【问题描述】:

在下面的代码中,映射键可以直接使用,也可以存储在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)
}

最后一行显示的完整错误是:

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

找到:Main.kk.key.type(底层类型为FooKey)

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

这是什么原因?为什么密钥一旦存储在case class 中就不再被接受并且类型检查失败?

【问题讨论】:

  • 这里有一些编译器的东西。 val m : Map[FooKey, String] = Map(KeyA -> "A", KeyB -> "B") m(kk.key) 似乎有效。

标签: scala dictionary types


【解决方案1】:

这是由于以下行推断出的密钥类型:

val m = Map(KeyA -> "A", KeyB -> "B")

如果您查看 REPL,它会告诉您它看到了 Map[Product with Serializable with FooKey,String]。这是因为KeyAKeyB 的常见超类型就是这样。案例类为您提供 Product 特征,允许迭代产品元素,定义 equalshashCode

所以你应该注释你的地图:

val m = Map[FooKey, String](KeyA -> "A", KeyB -> "B")

或者你定义

sealed trait FooKey extends Product with Serializable

【讨论】:

  • 还有另一种选择,我可以指定其中一个键以从可能的键类型中消除Productval m = Map((KeyA:FooKey) -> "A", KeyB -> "B")
  • 您使用的是哪个版本的 Scala?在 Scala 2.11 中,案例类和案例对象都实现Product
  • 作为一个特征,FooKey 在定义上是抽象的,不需要实现任何东西。
  • 你是对的。我把它误认为是sealed class(它在我的原始示例中表现出相同的行为)。
【解决方案2】:

正如0__the answer 中解释的那样,这是因为使用case objects 作为映射键的结果是m 的类型不是FooKey,而是Product with Serializable with FooKey

可以通过使用普通的objects 而不是case objects 来避免这种情况:

sealed trait FooKey
object KeyA extends FooKey
object KeyB extends FooKey

一个可能的缺点是使用了default Java Object hashCode,这可能不如case objects 提供的合理。

【讨论】:

  • 简而言之,正确的方法是将密钥类型明确指定为FooKey
猜你喜欢
  • 1970-01-01
  • 2012-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-25
  • 1970-01-01
  • 1970-01-01
  • 2012-03-10
相关资源
最近更新 更多