Scala概述(五)抽象(1.1、1.2)

参数限定(Parameter bounds考虑这样一个方法:updateMax,他将一个cell的值设置为其当前值与一个给定值之间较大的那个。我们希望这个函数能够作用于所有的cell类型,只要其值类型能够按照一个特征(traitOrdered定义的“<”操作符进行比较。目前假定这个特征定义如下:(更精确的定义在Scala标准类库中)

trait Ordered[T] {

def < (x: T): boolean

}

这样,updateMax方法可以通过如下方式进行泛型定义,其中使用到的方法称为限定多态(Bounded polymorphism):

def updateMax[T <: Ordered[T]](c: GenCell[T], x: T) =

if (c.get < x) c.set(x)

这里,类型参数定义子句[T <: Ordered[T]]引入了受限类型参数T,它限定参数类型T必须是Ordered[T]的子类型。这样,“<”操作符就可以应用于类型为T的参数了。同时,这个例子还展现出一个受限参数类型本身可以作为其限定类型的一部分,也就是说Scala支持F-受限多态(F-bounded polymorphism[10])。

协变性(Variance泛型和子类型(subtyping)组合在一起产生这样一个问题:它们如何相互作用。如果C是一个类型构造子(type constructor),ST的一个子类,那么C[S]是不是也是C[T]的子类呢?我们把有这种特性的类型构造子称为协变的(covariant)。可以看出GenCell这个类型构造子显然不是协变的,否则的话,下面这段代码就是合法的,但实际上它将会在运行时抛出错误:

val x: GenCell[String] = new GenCell[String]("abc")

val y: GenCell[Any] = x; // illegal!

y.set(1)

val z: String = y.get

GenCell中的可变(mutable)变量使其无法成为协变的。实际上,GenCell[String]不是GenCell[Any]的子类,因为有些可以针对GenCell[Any]的操作不能应用于GenCell[String],例如将其设置一个整型值。

另一方面,对于不可变数据类型,构造子的协变性是很自然成立的。例如:一个不可变的整数列表自然可以被看做是一个Any列表的特例。此外,在另一些情况下我们正好需要逆协变性(contravariance),例如一个输出管道Chan[T],有一个以T为类型参数的写操作,我们自然希望对于所有T<:S,都有Chan[S]<:Chan[T]

Scala允许通过“+/-”定义类型参数的协变性,用“+”放在类型参数前表示构造子对于该参数是协变的,“-”则表示逆协变,没有任何符号则表示非协变。

下面的GenList定义了一个协变的列表,包含isEmptyheadtail等三个方法。

abstract class GenList[+T] {

def isEmpty: boolean

def head: T

def tail: GenList[T]

}

Scala的类型系统通过跟踪类型参数的每一次使用来确保协变性确实成立。这些使用位置被分为几类:出现在不可变字段和方法返回结果被认为是协变的;出现在方法参数和类型参数的上/下界时被认为是逆协变的;非协变的类型参数永远出现在非协变的位置;在一个逆协变类型参数的内部,协变与逆协变是反转的。类型系统保证协变(逆协变)的类型参数总是出现在协变(逆协变)的位置上。(这段话叙述比较抽象,没有给出任何例子。由于是在说明Scala编译器在协变这个概念上的实现机制,不关心语言实现细节的话可以在一定程度上忽略——译注)

下面是GenList的两个实现:

object Empty extends GenList[Nothing] {

def isEmpty: boolean = true

def head: Nothing = throw new Error("Empty.head")

def tail: GenList[Nothing] = throw new Error("Empty.tail")

}

class Cons[+T](x: T, xs: GenList[T])

extends GenList[T] {

def isEmpty: boolean = false

def head: T = x

def tail: GenList[T] = xs

}

注意:Empty对象代表一个空列表,其元素可以是任何类型。这一点就是由协变性保证的,因为Empty的类型是GenList[Nothing],对于任何T而言,它都是GenList[T]的子类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值