在发布这个问题之前,我已阅读过这篇文章和这篇文章,但是我对这个主题的理解仍不够清晰,具体如下:
我了解协变和逆变分别表示什么。
如果我有以下类:
class Car {}
class SportsCar extends Car {}
class Ferrari extends SportsCar {}
而且:
object covar extends App {
// Test 1: Works as expected
def test1( arg: SportsCar => SportsCar ) = {
new SportsCar
}
def foo1(arg: Car): Ferrari = { new Ferrari }
def foo2(arg: SportsCar): Car = { new Ferrari }
def foo3(arg: Ferrari): Ferrari = { new Ferrari }
test1(foo1) // compiles
test1(foo2) // Fails due to wrong return type - violates return type is covariant
test1(foo3) // Fails due to wrong parameter type - violates param type is contravariant
// Test 2: Confused - why can I call test2 succesfully with ferrari
// as the parameter, and unsuccesfully with a car as the parameter?
def test2(arg: SportsCar): SportsCar = {
new Ferrari
}
val car = new Car()
val sportsCar = new SportsCar()
val ferrari = new Ferrari()
val f1 = test2(ferrari) // compiles - why?
val f2 = test2(car) // fails - why?
}
如上所述,在Test 2中,为什么我可以成功地使用ferrari作为参数调用test2,并且不能成功地使用car作为参数调用呢?
声明函数在其参数类型上是反变的,在其返回类型上是协变的是否只适用于作为参数传递的函数?我猜我没有适当区分该声明和我编写的那两个测试之间的差异。
test2
与test1
关系不是很大。第一个测试考察的是函数本身的子类型关系,而第二个测试则考察普通旧类的子类型关系。 - insan-eFerrari
都是一个SportsCar
,并且应该以这种方式对待。这就是为什么当期望基类时可以传递特定的类,但不能反过来,就像最后一行一样。 - insan-e