【问题标题】:Functions are contravariant in their argument types and co-variant in their return types函数的参数类型是逆变的,返回类型是协变的
【发布时间】:2017-05-13 13:54:10
【问题描述】:

在发布这个问题之前,我已经阅读了thisthis 的答案,但我对这个主题的理解仍然有点不清楚,如下所述:

我理解协变和逆变独立的含义。

如果我有以下课程:

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成功,而以a car为参数调用失败?

函数的参数类型是逆变的,返回类型是协变的语句是否只适用于作为参数传递的函数?我想我没有在语句和我编写的 2 个测试之间做出适当的区分。

【问题讨论】:

  • test2test1 没有太大关系。第一个检查functions 本身的子类型关系,第二个检查普通旧类的子类型。
  • 通过使你的类层次结构你说每个Ferrari IS-A SportsCar,它应该被这样对待。这就是为什么你可以在考虑基类时传递一个特定的类,但不能反过来,就像最后一行一样。

标签: scala covariance contravariance


【解决方案1】:

那是因为您将 subtypingco/contravariance 混合在一起。

在您的第一个示例中,您期望Function1[-T, +R]。在这种情况下,协/逆变规则适用于函数类型。在您的第二个示例中,您遵循简单的子类型规则。

test1 中,您传入foo1Car => Ferrari 一切正常,因为foo1 期望Car,但得到SportsCar,即Car。由于子类型的性质,任何需要Car 的方法都可以处理子类型。但是当我们单独讨论子类型时,这些规则就不起作用了。

如果我们用实际类型扩展test1foo1,也许会更清楚:

foo1:

  • 参数类型:
    • 期待:Car
    • 实际:SportsCar
  • 返回类型:
    • 期待:SportsCar
    • 实际:Ferrari

一切都安排妥当。

test2 中,规则发生了变化。如果我期望 SportsCar 你传入 any car,那么我不能再依赖输入是一辆跑车并且一切都坏了,但是如果你传入一辆实际上是跑车的法拉利,一切都很好。

再次,让我们排列类型:

测试2:

  • 第一种情况:
    • 参数类型:
      • 期待:SportsCar
      • 实际:Ferrari(子类型)
    • 结果:大家都很开心
  • 第二种情况:
    • 参数类型:
      • 期待:SportsCar
      • 实际:Car
    • 结果:错误。我们不确定这辆车是不是真正的跑车。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-06
    • 1970-01-01
    • 1970-01-01
    • 2012-10-30
    • 2012-04-07
    • 2022-08-05
    • 2012-07-24
    相关资源
    最近更新 更多