1

我无法理解 scala 的类型系统问题。下面的代码片段说明了这个问题。能够在可以具有 A 类型的键或 A 的子类型的类中拥有映射成员的正确方法是什么?我认为第二种方法是正确的,但是当我尝试从地图中获取元素时出现错误。这与存在类型有关吗?

sealed abstract class MyBaseType
case class Concrete1() extends MyBaseType
case class Concrete2() extends MyBaseType

case class DictVariant1(data: Map[MyBaseType, Double])
case class DictVariant2(data: Map[_ <: MyBaseType, Double])

object App {
  def main(args: Array[String]) {
    val d = List((Concrete1(), 3.5)).toMap

    /* this fails with:
     * type mismatch;  
     * found: scala.collection.immutable.Map[Concrete1,Double]  
     * required: Map[MyBaseType,Double] 
     * Note: Concrete1 <: MyBaseType, but trait Map is invariant in type A. 
     * You may wish to investigate a wildcard type such as `_ <: MyBaseType`. 
     * (SLS 3.2.10)
     * 
     */
    val dv1 = DictVariant1(d)
    dv1.data.get(d)

    /* Works fine */
    val dv2 = DictVariant2(d)

    /* this fails with:
     * type mismatch;  
     * found: d.type (with underlying type scala.collection.immutable.Map[Concrete1,Double])  
     * required: _$1    
     * 
     */
    dv2.data.get(Concrete1())
  }
}
4

1 回答 1

1

除非您明确要求将密钥恢复为静态正确的子类型(这似乎不太可能),否则以下操作将起作用:

case class DictVariant1(data: Map[MyBaseType, Double])
val d = List((Concrete1() : MyBaseType, 3.5)).toMap
val dv1 = DictVariant1(d)

使用类型归属强制Concrete1()被视为基本类型的实例;如果您将显式类型添加到d

val d : Map[MyBaseType, Double] = ....

或者,如果您放入多个条目以使类型推断器选择基本类型:

val d = List((Concrete1(), 3.5), (Concrete2(), 4.5)).toMap

但是,您使用的“获取”总是会失败,因为您试图将整体Map用作索引:如果您提供一个合理的密钥,它就可以正常工作:

dv1.data.get(Concrete1())
于 2013-07-01T08:38:49.120 回答