使用密封特质作为映射的键

6

我正在尝试从一个密封特质的实例定义一个映射。在下面的代码中,Scala似乎会将键类型推断为Product with Serializable with 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, 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)

我可以在m的定义中更改键类型,但这意味着需要在多个地方重复使用Product with Serializable with Day。我找到的另一种选择是更改特质的定义为:

sealed trait Day extends Product with Serializable

由于使用封闭特征和case对象而不是枚举有许多优点,因此我想知道在地图中将它们作为键的好方法是什么。


因为Map需要键具有在ProductSerializable中定义的属性,所以Scala会隐式地创建匿名类,该类扩展了您的类,并提供了equalshash的默认实现。 - sarveshseri
2
类型推断只需要一些帮助。这个可以工作:val m: Map[Day, Int] = Map[Day, Int](Sunday -> 17, Monday -> 4).withDefaultValue(0) - Rüdiger Klaehn
2个回答

4

由于 Map 需要键具有在 ProductSerializable 中定义的属性,因此Scala会隐式地创建一个继承您的类并带有 ProductSerializable 的匿名类,该类提供了 equalshash 的默认实现。

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)
}

1
您看到这个错误的根本原因是,默认情况下编译器会推断出最具体的类型,本例中为Product with Serializable with Test.Day。Scala中所有case类和case对象都隐式实现了ProductSerializable类,因此所有case对象都有它们的共同点。因此,这确实是SundayMonday的最具体公共类型。 另一方面,特质没有实现ProductSerializable
因此,当您在某处需要Day时,更具体的推断类型将无法满足要求(还因为,正如错误消息所指示的那样,MapK类型参数是不变的)。

一种方法,如Sarvesh Kumar Singh的答案所示,是使您的特征扩展ProductSerializable,但在我看来更好的方法(由Rüdiger Klaehn指出)是通过明确类型告诉编译器您实际上对更一般的类型Map [Day,Int] 感到满意:

val m = Map[Day, Int](Sunday -> 17, Monday -> 4).withDefaultValue(0)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接