函数在其参数类型上是协变的,在其返回类型上是逆变的,例如:
trait Function1[-T1, +R] extends AnyRef
trait Function2[-T1, -T2, +R] extends AnyRef
在这里,T1
、T2
、...、T
n(其中n ≤ 22
)是参数,R
是返回类型。
在高阶函数中(接受函数作为参数的函数),一个参数可以具有传递到函数中的类型参数,例如trait Iterable
中的foldLeft
函数。
Iterable
声明如下:
trait Iterable[+A] extends AnyRef
而foldLeft
被声明为
def foldLeft[B](z : B)(op : (B, A) => B) : B
由于A
被声明为协变,因此它可以用作返回类型。但是在这里它是一个参数类型,因为
trait Function2[-T1, -T2, +R] extends AnyRef
op: (B, A) => B
是Function2
的文本类型,所以需要将其作为参数传递。Function2
在其参数类型上是反变的。这被称为方差翻转:特征
Function2
在其参数类型上是反变的。
首先,将函数视为类或者是一个 typeclass
。考虑它的类型 Function1[-A,+B]
。
假设我们有以下代码:
class x
class y extends b
现在我有两个如下所示的函数:
val test1:x=>Int = //do something
val test2:y=>int = //do something
现在如果我有另一个像下面这样的方法,
def acceptFunction(f: y => Unit, b: B) = //do something
根据类型签名Function1[-A,+B]
,由于逆变性
,我可以将test2
和test1
传递给acceptFunction
。
有点像test1<:test2
。
这与说函数的参数是协变的是完全不同的事情。
class Fruit { def name: String="abstract" }
class Orange extends Fruit { override def name = "Orange" }
class Apple extends Fruit { override def name = "Apple" }
testM(new Apple())
def testM(fruit:Fruit)={}
但你不能写这个,
testM(new Fruit())
def testM(fruit:Apple)={}