为什么从案例 class 中提取时映射键类型不起作用?
Why does not Map key type work when extracted from a case class?
在下面的代码中,映射键可以直接使用,也可以存储在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)
}
最后一行显示的完整错误是:
Error:(16, 8) type mismatch;
found : Main.kk.key.type (with underlying type FooKey)
required: Product with Serializable with FooKey
这是什么原因?为什么密钥一旦存储在 case class
中就不再被接受并且无法通过类型检查?
这是因为以下行推断出密钥的类型:
val m = Map(KeyA -> "A", KeyB -> "B")
如果您查看 REPL,它会告诉您它看到 Map[Product with Serializable with FooKey,String]
。这是因为 KeyA
和 KeyB
的普通超类型就是这样。 Case 类 为您提供 Product
特征,允许迭代产品元素,定义 equals
和 hashCode
.
所以你应该在你的地图上添加注释:
val m = Map[FooKey, String](KeyA -> "A", KeyB -> "B")
或者你定义
sealed trait FooKey extends Product with Serializable
如 by 0__ 中所述,这是因为使用 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
提供的合理。
在下面的代码中,映射键可以直接使用,也可以存储在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)
}
最后一行显示的完整错误是:
Error:(16, 8) type mismatch;
found : Main.kk.key.type (with underlying type FooKey)
required: Product with Serializable with FooKey
这是什么原因?为什么密钥一旦存储在 case class
中就不再被接受并且无法通过类型检查?
这是因为以下行推断出密钥的类型:
val m = Map(KeyA -> "A", KeyB -> "B")
如果您查看 REPL,它会告诉您它看到 Map[Product with Serializable with FooKey,String]
。这是因为 KeyA
和 KeyB
的普通超类型就是这样。 Case 类 为您提供 Product
特征,允许迭代产品元素,定义 equals
和 hashCode
.
所以你应该在你的地图上添加注释:
val m = Map[FooKey, String](KeyA -> "A", KeyB -> "B")
或者你定义
sealed trait FooKey extends Product with Serializable
如 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
提供的合理。