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]的子類型。

發佈了16 篇原創文章 · 獲贊 1 · 訪問量 2189
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章