Scala协方差

Scala协方差,scala,covariance,contravariance,Scala,Covariance,Contravariance,我是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

我是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  }
更新 实际上,这就像把一个参数传递给函数,所以我有一个参数可以是逆变的[-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
你的


可以接受一个
MyOtherSubClass
作为参数,例如
f(新MyOtherSubClass())
,但这将调用
f4(新MyOtherSubClass())
。但是
MyOtherSubClass
不是
MySubClass
,因此您可能会使用错误的类型调用
f4
,您的代码将无法编译,否则,例如,如果您有

class MyOtherSubClass extends MyClass
你的


可以接受一个
MyOtherSubClass
作为参数,例如
f(新MyOtherSubClass())
,但这将调用
f4(新MyOtherSubClass())
。但是
MyOtherSubClass
不是
MySubClass
,因此调用
f4
时使用了错误的类型

让我们查看
printCarInfo
参数。接受
Car
作为参数并返回
AnyRef
getCarInfo:Car=>AnyRef
的函数很少

在scala中,这种带有一个参数的函数可以使用
trait Function1[-T,+S]扩展AnyRef

功能1
-T
+S
两种类型参数化。第一种类型表示函数的参数<代码>汽车在我们的案例中。它是一个反差(减号),这意味着您可以传递任何
超级类型
+S
表示返回类型及其协变(加号),这意味着您可以传递任何子类型

调用了
printCarInfo
并传递了
Vehicle=>String类型的参数。
Vehicle是Car的超级类型,String是AnyRef的子类型,所以它满足条件

那么,为什么参数的位置是反变的,返回类型是协变的呢。让我们尝试为参数假设相反的结果:

printCarInfo
accept函数类型:
Vehicle=>AnyRef
getOwnerInfo
is
Car=>AnyRef

当您试图实现printCarInfo时,我们可以处理任何争论,不仅仅是汽车,还有卡车和自行车。 显然,调用
Printer.printCarInfo(getOwnerInfo)
失败,因为您试图从卡车或自行车获取ownerinfo,而您的方法实现只能处理汽车。 希望这是清楚的


关于你的代码。相反:您可以指定
f4:mysubclass=>Boolean=f
,它将起作用。

让我们查看
printCarInfo
参数。接受
Car
作为参数并返回
AnyRef
getCarInfo:Car=>AnyRef
的函数很少

在scala中,这种带有一个参数的函数可以使用
trait Function1[-T,+S]扩展AnyRef

功能1
-T
+S
两种类型参数化。第一种类型表示函数的参数<代码>汽车
在我们的案例中。它是一个反差(减号),这意味着您可以传递任何
超级类型
+S
表示返回类型及其协变(加号),这意味着您可以传递任何子类型

调用了
printCarInfo
并传递了
Vehicle=>String类型的参数。
Vehicle是Car的超级类型,String是AnyRef的子类型,所以它满足条件

那么,为什么参数的位置是反变的,返回类型是协变的呢。让我们尝试为参数假设相反的结果:

printCarInfo
accept函数类型:
Vehicle=>AnyRef
getOwnerInfo
is
Car=>AnyRef

当您试图实现printCarInfo时,我们可以处理任何争论,不仅仅是汽车,还有卡车和自行车。 显然,调用
Printer.printCarInfo(getOwnerInfo)
失败,因为您试图从卡车或自行车获取ownerinfo,而您的方法实现只能处理汽车。 希望这是清楚的

关于你的代码。相反:你可以分配
f4:mysubclass=>Boolean=f
,它会工作。

可能重复的可能重复的可能重复的我理解所有的,除了“关于你的代码。它是相反的:你可以分配f4:mysubclass=>Boolean=f,它会工作。”请解释它是如何反向的?我理解所有的,除了“那么关于你的代码。相反,你可以指定f4:MysSubClass=>Boolean=f,它就会工作?
val f: (MyClass) => Boolean