十一,类型参数化

来源:互联网 发布:ubuntu登录界面 编辑:程序博客网 时间:2024/06/05 08:16

类型参数化

 

在scala中,类型参数化(类似于泛型)使用方括号实现,如:Foo[A],同时,我们称Foo为高阶类型。如果一个高阶类型有2个类型参数,则在声明变量类型时可以使用中缀形式来表达,此时也称该高阶类型为中缀类型,示例如下:

         class Foo[A,B]

         val x:Int Foo String = null     // Int FooString 等同于 Foo[Int,String]

 

与java相似,scala的类型参数化也使用类型擦除实现(类型擦除是很差劲的泛型机制,不过可能是由于java的原因,scala也这样做了),类型擦除的唯一例外就是数组,因为在scala中和java中,它们都被特殊处理,数组的元素类型与数组值保存在一起。scala中,数组是“不变”的(这点与java不同),泛型默认是“不变”的

 

协变逆变不变

         拿Queue为例,如果S是T的子类型,那么Queue[S]是Queue[T]的子类型,就称Queue是协变的;相反,如果Queue[T]是Queue[S]的子类型,那么Queue是逆变的;既不是协变又不是逆变的是不变的,不变的又叫严谨的。

在scala中,泛型默认是不变的。当定义类型时,你可以在类型参数前加上“+”使类型协变,如Queue[+A]。类似地,你可以在类型参数前加上“-”使类型逆变。在java中使用类型时可以通过使用extends和super来达到协变逆变的目的,它们都是“使用点变型”,java不支持“声明点变型”。而scala中同时提供了声明点变型(“+”和“-”,它们只能在类型定义时使用)和使用点变型(“<:”和“>:”,类似于java中的extends和super,在使用类型时声明)。不管是“声明点变型”还是“使用点变型”,都遵循PECS法则,详见java泛型。需要注意的是:变型并不会被继承,父类被声明为变型,子类若想保持仍需要再次声明。

 

继承中的协变逆变

         c++、java、scala都支持返回值协变,也就是说在继承层次中子类覆盖超类的方法时,可以指定返回值为更具体的类型。c#不支持返回值协变。

允许参数逆变的面向对象语言并不多——c++、java、scala和c#都会把它当成一个函数重载。


原创粉丝点击