首页 > 解决方案 > Scala协变,逆变混淆

问题描述

我是 Scala 的新手,这真的很混乱。请帮我。

/**
2    * Remember! In Scala, every function that takes one argument 
3    * is an instance of Function1 with signature:
4    *
5    * trait Function1[-T, +S] extends AnyRef
6    */
7   
8   class Vehicle(val owner: String)
9   class Car(owner: String) extends Vehicle(owner)
10  
11  object Printer {
12
13    val cars = List(new Car("john"), new Car("paul"))
14
15    def printCarInfo(getCarInfo: Car => AnyRef) {
16      for (car <- cars) println(getCarInfo(car))
17    }
18  }
19  
20  object Customer extends App {
21
22   val getOwnerInfo: (Vehicle => String) = _.owner
23   
24   Printer.printCarInfo(getOwnerInfo)
25  }

此代码取自https://medium.com/@sinisalouc/variance-in-java-and-scala-63af925d21dc

规则是:

函数输入类型协变而返回类型逆变的规则来自 Liskov 替换原则 (LSP)。它说 T 是 U 的子类型,如果它支持与 U 相同的操作,并且它的所有操作比 U 中的相应操作需要更少(或相同)并提供更多(或相同)(子类型是自反的,所以 S <: S )。

所以我的问题是,如果我可以传递一个需要超类型的子类型(在代码行号 15 和 22 之上),那么为什么下面的代码不起作用?

class MyClass extends AnyRef
class MySubClass extends MyClass

abstract class Class {
  val f1: (Any) => Any = ???
  val f2: (Any) => Boolean = ???
  val f3: (MyClass) => Any = ???
  val f4: (MySubClass) => Boolean = ???
  val f5: (Any) => Nothing = ???
  val f6: (MyClass) => Null = ???

  val f: (MyClass) => Boolean = f4; //Error
}

更新 所以实际上它就像将参数传递给函数所以我有参数可以是逆变的 [-T] 并且返回可以是协变的 [+S]

    class MyClass extends AnyRef
    class MySubClass extends MyClass

    abstract class Class {
      val f1: (Any) => Any = ???
      val f2: (MyClass) => Boolean = ???
      val f3: (MyClass) => Any = ???
      val f4: (MySubClass) => Boolean = ???
      val f5: (Any) => Nothing = ???
      val f6: (MyClass) => Null = ???

      val f: (MySubClass) => AnyVal = f2
}

这是一个有效的代码,MyClass就像在层次结构中上升一样,Boolean就像在层次结构中下降一样。

标签: scalacovariancecontravariance

解决方案


您的代码将无法编译,否则例如如果您有

class MyOtherSubClass extends MyClass

您的

val f: (MyClass) => Boolean

可以接受 aMyOtherSubClass作为参数,例如f(new MyOtherSubClass()),但那将是调用f4(new MyOtherSubClass()). 但MyOtherSubClass不是 a MySubClass,所以你会f4用错误的类型调用


推荐阅读