Scala 使用密封特征作为地图的键
我试图从一个封闭特征的实例中定义一个映射。在下面的代码中,Scala似乎将密钥类型推断为可序列化为Day的Scala 使用密封特征作为地图的键,scala,traits,Scala,Traits,我试图从一个封闭特征的实例中定义一个映射。在下面的代码中,Scala似乎将密钥类型推断为可序列化为Day的产品: object Test extends App { sealed trait Day case object Sunday extends Day case object Monday extends Day case object Tuesday extends Day val m: Map[Day, Int] = Map(Sunday -> 17, M
产品
:
object Test extends App {
sealed trait Day
case object Sunday extends Day
case object Monday extends Day
case object Tuesday extends Day
val m: Map[Day, Int] = Map(Sunday -> 17, Monday -> 4).withDefaultValue(0)
}
这不会编译:
Test.scala:7: error: type mismatch;
found : scala.collection.immutable.Map[Product with Serializable with Test.Day,Int]
required: Map[Test.Day,Int]
Note: Product with Serializable with Test.Day <: Test.Day, but trait Map is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: Test.Day`. (SLS 3.2.10)
val m: Map[Day, Int] = Map(Sunday -> 17, Monday -> 4).withDefaultValue(0)
由于使用密封的trait和case对象而不是enum有很多优点,我想知道将它们作为键放入映射中的好方法是什么。因为
map
需要键具有在Product
和Serializable
中定义的属性,因此Scala隐式创建了匿名类
,该类使用产品
和可序列化
扩展类,后者提供了等于
和哈希
的默认实现
object Test extends App {
trait PS extends Product with Serializable
sealed trait Day extends PS
case object Sunday extends Day
case object Monday extends Day
case object Tuesday extends Day
val m: Map[Day, Int] = Map(Sunday -> 17, Monday -> 4).withDefaultValue(0)
}
你看到这一点的根本原因是
产品。Product
和Serializable
类由Scala中的所有case类和case对象隐式实现,因此所有case对象都有它们的共同点。因此,这确实是周日
和周一
最常见的类型
产品
或可序列化
Day
时,更具体的推断类型将不起作用(也因为,如错误消息所示,Map
的K
类型参数是不变的。)
一种方法,正如Sarvesh Kumar Singh的回答所指出的那样,是让您的trait扩展产品和可序列化,但在我看来,更好的方法(由Rüdiger Klaehn指出)是通过使类型显式化,告诉编译器您实际上可以使用更通用的映射[Day,Int]
:
val m = Map[Day, Int](Sunday -> 17, Monday -> 4).withDefaultValue(0)
因为Map需要键具有在Product
和Serializable
中定义的属性,因此Scala隐式地创建了匿名类,该类使用Product
和Serializable
扩展类,后者提供了equals
和hash
的默认实现。类型推断只需要一些帮助。这是有效的:val m:Map[Day,Int]=Map[Day,Int](星期日->17,星期一->4)。使用默认值(0)
val m = Map[Day, Int](Sunday -> 17, Monday -> 4).withDefaultValue(0)