类型的scala类型错误,地图成员使用存在类型键入

时间:2013-07-01 08:20:51

标签: scala

我有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())
  }
}

1 个答案:

答案 0 :(得分: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

&#39; get&#39;但是,你使用总是会失败,因为你试图使用整个Map作为索引:如果你提供了一个合理的密钥,它可以正常工作:

dv1.data.get(Concrete1())