函数的参数类型是逆变的,而返回类型是协变的。

18

在发布这个问题之前,我已阅读过这篇文章这篇文章,但是我对这个主题的理解仍不够清晰,具体如下:

我了解协变和逆变分别表示什么。

如果我有以下类:

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作为参数调用呢?

声明函数在其参数类型上是反变的,在其返回类型上是协变的是否只适用于作为参数传递的函数?我猜我没有适当区分该声明和我编写的那两个测试之间的差异。


test2test1关系不是很大。第一个测试考察的是函数本身的子类型关系,而第二个测试则考察普通旧类的子类型关系。 - insan-e
通过创建你的类层次结构,你在说每个Ferrari都是一个SportsCar,并且应该以这种方式对待。这就是为什么当期望基类时可以传递特定的类,但不能反过来,就像最后一行一样。 - insan-e
1个回答

15
那是因为你混淆了子类型和协变/逆变。
在第一个例子中,你期望一个Function1[-T, +R]。在这种情况下,协变/逆变规则适用于函数类型。在第二个例子中,你遵循简单的子类型规则。
在test1中,你传入了foo1,它是Car => Ferrari,一切都正常,因为foo1期望一个Car,但得到了SportsCar,它是一个Car的子类型。任何需要Car的方法都可以处理子类型,因为它们是子类型性质。但是,当我们仅谈论子类型时,这些规则不起作用。
如果我们用实际类型扩展带有foo1的test1,或许会更清晰:
foo1:
- 参数类型: - 期望值:Car - 实际值:SportsCar - 返回类型: - 期望值:SportsCar - 实际值:Ferrari
一切都很顺利。
在test2中,规则发生了变化。如果我期望一个SportsCar,你传入了任何车,那么我不能再依赖于输入是一辆运动汽车,一切都会崩溃,但如果你传入一辆实际上是一辆运动汽车的法拉利,一切都没问题。
同样,让我们排列一下类型:
test2:
- 第一种情况: - 参数类型: - 期望值:SportsCar - 实际值:Ferrari(子类型) - 结果:大家都很开心 - 第二种情况: - 参数类型: - 期望值:SportsCar - 实际值:Car - 结果:错误。我们不确定车是否真的是一辆运动汽车。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接