scala中函数类型的多态

因为Function的泛型里定义了函数入参和出参分别是“逆变”“协变”的:
[scala]trait Function1[-T1, +R] {…}[/scala]

所以A=>B这样的函数类型,也可以有继承关系的。
我们做个测试,先简单些,只看出参类型的(协变容易理解些),A=>BA=>C两个函数类型;
如果C extends BA=>CA=>B的子类型
[scala]scala> class A; class B; class C extends B

//定义A=>C类型的函数
scala> val t2 = (p:A)=>new C

//可以把 A=>C类型的函数赋值给 A=>B类型的
scala> val t3:A=>B = t2

//或直接把t2造型为 A=>B
scala> t2.asInstanceOf[A=>B]
[/scala]
再看看入参类型,这个是逆变,继承关系正好相反。
假设: X=>R,Y=>R 如果 Y extends XX=>RY=>R 的子类型
[scala]scala> class R; class X; class Y extends X

//定义X=>R类型的函数
scala> val f1 = (x:X)=>new R

//把X=>R类型的函数赋值给 Y=>R 类型的
scala> val f2:Y=>R = f1

//或直接造型
scala> f1.asInstanceOf[Y=>R]
[/scala]
协变和逆变的场景与java泛型的”PECS原则”一致

注: PECS 是Joshua Bloch在《Effictive Java》里提出的一个原则。
当参数(容器)是一个生产者(producer)提供元素给你的代码来用(即容器只读),那么容器的泛型应该使用:

Collection< ? extends T >


当参数(容器)作为一个消费者(consumer)来消费你提供的数据(即容器可写),那么容器的泛型应该使用:

Collection< ? super T >

1 thought on “scala中函数类型的多态

  1. Pingback: Scala Convariance and Contravariance(逆变与协变) | 小白菜

Leave a Reply

Your email address will not be published. Required fields are marked *