Kri*_*ala 7 scala case-class default-arguments
请考虑以下内容(使用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
更改它以val dogMap = AnimalsMap[Dog](Map())修复它,但不再利用默认参数值.
为什么默认值被推断为Map [Nothing,Nothing],因为List对应物按预期工作?有没有办法创建一个使用maparg 默认值的AnimalsMap实例?
编辑:我已经接受了我更紧迫的第二个问题的答案,但我仍然有兴趣知道为什么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
Itt*_*ayD 20
Scala有一个功能,您可以在其通用参数中定义一个协变/逆变的类.
作为协方差的一个例子:很自然地认为如果class Student extends Person那么List[Student]"延伸" List[Person].这是因为接受a的每个方法List[Person]在处理对象时应该没有问题List[Student].这在Java中是不可能的(不使该方法也是通用的).
逆变是相反的,解释起来有点棘手.当类型应该被推送到泛型类而不是读取时(在List[Person]您阅读列表的元素时)是必需的.一般示例是函数.函数的参数类型被放入其中,因此如果一个方法需要一个函数,Person => String它就不能用一个函数Student => String调用(它会调用一个人的参数,但它需要一个学生)
Scala还定义Nothing了隐式扩展所有内容.它是底部类型.所以List[Nothing]总是"扩展" List[X]任何X. List()创建List[Nothing]和协方差是你可以写的原因val x: List[Person] = List().
无论如何,Map的键类型是不变的.原因是a Map[A, B]就像一个函数,A => B所以它只能是逆变的A.另一种方法是考虑如果你传递一个Map[Student, String]方法期待会发生什么Map[Person, String],显然它可能会尝试将Person对象放在那里不好,另一种方式是好的.另一方面,Map可以被视为Iterable[(A, B)],这里它应该是A中的协变.因此它的值是不变的.
结果是您无法将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]()
                       ^
只需给编译器一点帮助:
\n\ncase class AnimalsMap[A <: Animal](map:Map[String,A] = Map[String, A]())\n                                                          ^^^^^^^^^^^\n我将把为什么你的解决方案不起作用的详细信息留给更熟悉 Scala 类型推断的人\xe2\x80\xa6
\n\n编辑:请参阅IttayD 的答案以获取对此行为的很好解释。
\n| 归档时间: | 
 | 
| 查看次数: | 6050 次 | 
| 最近记录: |