Scala中有界类型参数化案例类和默认args的问题

|| 考虑以下内容(经过Scala 2.8.1和2.9.0测试):
trait Animal
class Dog extends Animal

case class AnimalsList[A <: Animal](list:List[A] = List())
case class AnimalsMap[A <: Animal](map:Map[String,A] = Map())

val dogList = AnimalsList[Dog]()  // Compiles
val dogMap = AnimalsMap[Dog]()    // Does not compile
最后一行失败:
error: type mismatch;
 found   : scala.collection.immutable.Map[Nothing,Nothing]
 required: Map[String,Main.Dog]
Note: Nothing <: String, but trait Map is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: String`. (SLS 3.2.10)
Error occurred in an application involving default arguments.
    val dogMap = AnimalsMap[Dog]()    // Does not compile
                       ^
one error found
将其更改为“ 2”可以修复该问题,但不再利用默认参数值。 考虑到List对应项按预期工作,为什么将默认值推断为Map [Nothing,Nothing]?有没有一种方法可以创建一个AnimalsMap实例,该实例使用
map
arg的默认值? 编辑:我已经接受了我提出的更为紧迫的第二个问题的答案,但是我仍然想知道为什么在这两种情况下,以不同的方式推断出
Map()
的键类型:
case class AnimalsMap1(map:Map[String,Animal] = Map())
val dogs1 = AnimalsMap1() // Compiles

case class AnimalsMap2[A <: Animal](map:Map[String,A] = Map())
val dogs2 = AnimalsMap2[Dog]() // Does not compile
编辑2:似乎类型界限是不相关的-案例类的任何参数类型都会引起问题:
case class Map3[A](map:Map[String,A] = Map())
val dogs3 = Map3[Dog]() // Does not compile
    
已邀请:
只是给编译器一些帮助:
case class AnimalsMap[A <: Animal](map:Map[String,A] = Map[String, A]())
                                                          ^^^^^^^^^^^
我将把您的解决方案为什么不起作用的详细信息留给更好地了解Scala类型推断的人…… 编辑:请参阅IttayD \的答案对此行为的一个很好的解释。     
Scala具有一项功能,您可以在其通用参数中将一个类定义为协变/逆变。 作为协方差的一个示例:很自然地认为,如果
class Student extends Person
,那么
List[Student]
\“扩展\”
List[Person]
。这是因为接受s10ѭ的每种方法在处理对象
List[Student]
时应该没有问题。这在Java中是不可能的(不使方法也通用)。 相反,相反是很难解释的。当类型应该被推到通用类而不是读取时是必需的(在
List[Person]
中,您将读取列表的元素)。一般的例子是一个函数。函数的参数类型已放入其中,因此,如果某个方法需要一个函数ѭ14can,则不能使用函数
Student => String
调用它(它将与一个人调用该参数,但希望有一个学生) Scala还定义了“ 16”来隐式扩展所有内容。它是底部类型。因此,对于任何X,
List[Nothing]
始终“扩展”“18ѭ。
List()
创建
List[Nothing]
,而协方差就是为什么您可以写
val x: List[Person] = List()
。 无论如何,Map的键类型是不变的。原因是
Map[A, B]
与函数
A => B
类似,因此它只能与
A
互变。另一种方法是思考如果将
Map[Student, String]
传递给期望
Map[Person, String]
的方法会发生什么,显然,它可能会尝试将
Person
对象放入其中,但效果不好,否则可以。另一方面,Map可以看成
Iterable[(A, B)]
,这里它在A中应该是协变的。因此它的值是不变的。 结果是您无法将
Map[Nothing, Nothing]
分配给类型
Map[String, Animal]
的变量。
Map()
创建
Map[Nothing, Nothing]
编译器告诉您:
scala> val dogs3 = Map3[Dog]()
<console>:13: error: type mismatch;
 found   : scala.collection.immutable.Map[Nothing,Nothing]
 required: Map[String,Dog]
Note: Nothing <: String, but trait Map is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: String`. (SLS 3.2.10)
Error occurred in an application involving default arguments.
       val dogs3 = Map3[Dog]()
                       ^
    

要回复问题请先登录注册