gpt4 book ai didi

scala - Scala 中的有界类型参数化案例类和默认参数存在问题

转载 作者:行者123 更新时间:2023-12-03 01:33:54 25 4
gpt4 key购买 nike

考虑以下内容(使用 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

将其更改为 valdogMap = AnimalsMap[Dog](Map()) 可以修复此问题,但不再利用默认参数值。

鉴于 List 对应项按预期工作,为什么默认值被推断为 Map[Nothing,Nothing]?有没有办法创建一个使用 map 参数默认值的 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

最佳答案

Scala 有一个功能,您可以将类定义为在其泛型参数中协变/逆变。

作为协方差的一个例子:很自然地认为如果 class Student extends Person 那么 List[Student] “extends” List[Person]。这是因为每个接受 List[Person] 的方法在处理对象 List[Student] 时应该没有问题。这在 Java 中是不可能的(不使该方法也通用)。

逆变则相反,并且解释起来有点棘手。当类型应该被推送到泛型类而不是读取时(在 List[Person] 中读取列表的元素),这是必需的。一般的例子是一个函数。函数参数的类型被放入其中,因此如果一个方法需要一个函数 Person => String ,则不能用函数 Student => String 调用它>(它将与一个人进行争论,但它期望的是一个学生)

Scala 还定义了 Nothing 来隐式扩展所有内容。这是底部类型。因此 List[Nothing] 总是“扩展”任何 X 的 List[X]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]()
^

关于scala - Scala 中的有界类型参数化案例类和默认参数存在问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6135663/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com