scala - 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
就像在层次结构中下降一样。
解决方案
您的代码将无法编译,否则例如如果您有
class MyOtherSubClass extends MyClass
您的
val f: (MyClass) => Boolean
可以接受 aMyOtherSubClass
作为参数,例如f(new MyOtherSubClass())
,但那将是调用f4(new MyOtherSubClass())
. 但MyOtherSubClass
不是 a MySubClass
,所以你会f4
用错误的类型调用
推荐阅读
- python - 我想使用 pyscreenshot 截取网页上特定区域的屏幕截图
- wordpress - 是否有 $content 变量可以通过过滤器修改页面内容?
- extjs - 自定义缓冲网格分页参数
- react-native - 不断收到“未定义不是对象(评估'this.props.navigation.navigate')”
- c# - 射击时如何仅减慢子弹速度?
- firebase - FireStore:查询 Firebase Auth 表?
- assembly - 使用 QtSpim 用 MIPS 代码判断素数
- angular - 如何在角度 2 中正确显示列表
- firebase-realtime-database - 使用 Firebase 过滤数据
- android - 在android中刷新片段时单选按钮不起作用