为什么像"cons[B >: A](v: B)"定义的方法接受不是 A 超类型的类型参数?



我现在正在研究scala中的方差,我认为我对反方差有很好的理解。例如,给定trait List[-A],我知道List[Int]List[AnyVal]的超类型。

但是说我有以下特点:

trait List[+A] {
def cons(hd: A): List[A]
}

为什么cons参数类型错误

为什么需要def cons[B >: A](v: B): List[B]

例如:

val animal_list: List[Animal] = List(tiger, dog)

如果我们呼叫:

animal_list.cons(tiger)

自从Tiger <: Animal以来,cons不是遇到了问题吗由于BTiger并且AAnimal并且B >: A不为真。

为什么cons的参数类型错误

trait List[+A] {
def cons(hd: A): List[A]
}

编译器会给您错误:
covariant type A occurs in contravariant position in type A of value hd
,因为方法参数算作逆变位置,但A是协变的

让我们想象一下,这个方法声明将被编译。然后我们可以做:

class ListImpl[A] extends List[A] {
override def cons(hd: A): List[A] = ???
}
val strings: List[String] = new ListImpl[String]
val values: List[Any] = strings // OK, since List[String] <: List[Any] (in List[A], A is covariant)
values.cons(13) // OK(??), since values's static type is List[Any], so argument of cons should be Any, and 13 conforms to type Any

上面最后一行真的可以吗?我们在values上呼叫consvaluesstrings相同,并且strings是类型为ListImpl[String]的对象。因此,最后一行中的cons调用需要String参数,但我们传递的是Int,因为values的静态类型是List[Any],而Int符合Any。这里肯定出了问题——该怪哪一行?答案是:cons方法声明。为了解决这个问题,我们必须从逆变位置删除协变类型参数A(在cons声明中)。或者,我们可以使CCD_ 32非协变。

另请参阅以下问题:#1、#2。

cons不是出了问题吗

trait List[+A] {
def cons[B >: A](v: B): List[B]
}
val animal_list: List[Animal] = List(tiger, dog)  // We are assuming that List.apply and concrete implementation of List is somewhere defined.

否,animal_list.cons(tiger)调用类型正确

假设AnimalDogTiger的公共超类型,dogtiger分别是DogTiger的实例。

animal_list.cons(tiger)调用中,AB类型参数都实例化为Animal,因此cons方法的形式为:

def cons[Animal >: Animal](v: Animal): List[Animal]

满足Animal >: Animal约束是因为:

超类型和子类型关系是自反的,这意味着类型既是其自身的超类型,也是其自身的子类型。[来源]

cons的参数是Tiger,它符合类型Animal,因此方法调用的类型正确。

请注意,如果强制将B实例化为Tiger,就像animal_list.cons[Tiger](tiger)一样,那么此调用的类型将不正确,并且会出现编译器错误。

请参阅此处的类似示例。

相关内容

  • 没有找到相关文章

最新更新