如何解决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]()
^
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。