類徘熔、特質(zhì)门躯、方法和函數(shù)都可以有類型參數(shù)
將類型參數(shù)放置在名稱之后,以方括號(hào)括起來
參數(shù)類型(不能什么都傳酷师,要加限定)
對(duì)于參數(shù)類型的 class 實(shí)際類型會(huì)在new對(duì)象時(shí)推斷
例如:class Pair[T, S](val first: T, val second: S)
val?p =?new?Pair(42,?"String")
參數(shù)類型界定
1讶凉、<: 和 >: (我定義為 “純子類界定”)
class Pair[T](val first: T, val second: T)
它要求 兩個(gè)參數(shù)類型相同
添加一個(gè)方法,返回較小的那個(gè)值:
? class Pair[T](val first: T, val second: T) {
? ? def smaller = if (first.compareTo(second) < 0) first else second
? }
這是錯(cuò)的山孔,因?yàn)槲覀儾⒉恢纅irst是否有compareTo方法懂讯,所以添加一個(gè)上界T<:Comparable[T]? (必須是以可比較的類型)
? class Pair[T <: Comparable[T]](val first: T, val second: T) {
? ? def smaller = if (first.compareTo(second) < 0) first else second
? }
原來給T什么都可以傳,現(xiàn)在就不行了饱须。
你也可以為類型指定一個(gè)下界(也就是要求是子類)域醇。
舉例,把第一個(gè)組件替換為子類蓉媳。
? class Person? class Student extends Person
? class Pair[T](val first: T, val second: T) {
? ? def replaceFirst(newFirst: T) = new Pair[T](newFirst, second)
? }
假定我們有一個(gè)Pair[Person]譬挚,我們想用Student 替換第一個(gè)類型,實(shí)際上這樣是不可行的酪呻,因?yàn)門必須一致减宣。因此,在函數(shù)后面定義下界玩荠。
? class Pair[T](val first: T, val second: T) {
? ? def replaceFirst[R >: T](newFirst: R) = new Pair[R](newFirst, second)
? }
2漆腌、<% 視圖界定 (我定義為:“含隱式條件的子類界定”)
前面有一個(gè)帶上界的示例:
把 前面的例子 class?Pair[T?<:?Comparable[T]]
如果你new一個(gè)Pair(4,2),編譯器會(huì)報(bào)錯(cuò)阶冈,Scala的Int類型并沒有實(shí)現(xiàn)Comparable闷尿。
解決辦法是使用視圖界定:
? class Pair[T <% Comparable[T]](val first: T, val second: T) {
? ? def smaller = if (first.compareTo(second) < 0) first else second
? }
<%?意味著 T 可以被隱式轉(zhuǎn)換成Comparable[Int]。
隱式類型轉(zhuǎn)換女坑,Int 轉(zhuǎn) RichInt 填具,RichInt實(shí)現(xiàn)了Comparable[Int]
3、T:M 上下文界定 (我定義為:“含隱式的子類界定”)
其中M是另一個(gè)泛型類。它要求必須存在一個(gè)類型為M[T]的“隱式值”劳景。也就是說必須把這個(gè)類型放在另外一個(gè)類型里
? class Pair[T : Ordering](val first: T, val second: T) {
? ? def smaller(implicit ord: Ordering[T]) =
? ? ? if (ord.compare(first, second) < 0) first else second
? }
4誉简、<% 上Manifest 上下文界定
Manifest were added specially to handle arrays
要實(shí)例化一個(gè)泛型的Array[T],我們需要一個(gè)Manifest[T]對(duì)象盟广。要想讓基本類型的數(shù)組能夠正常工作的話闷串,這是必須的。舉例來說筋量,如果T是Int烹吵,你會(huì)希望虛擬機(jī)中對(duì)應(yīng)的是一個(gè)int[]數(shù)組。在Scala中毛甲,Array只不過是類庫提供的一個(gè)類年叮,編譯器并不對(duì)它做特殊處理。如果你要編寫一個(gè)泛型函數(shù)來構(gòu)造泛型數(shù)組的話玻募,你需要傳入這個(gè)Manifest對(duì)象來幫忙。由于它是構(gòu)造器的隱式參數(shù)一姿,你可以用上下文界定:
? def makePair[T: Manifest](first: T, second: T) = {
? ? val r = new Array[T](2)
? ? r(0) = first
? ? r(1) = second
? }
類型約束
類型約束提供的是另一個(gè)限定類型的方式七咧。總共有三種關(guān)系可供使用:
T=:=U?測(cè)試T是否等于U
T<:
T<%
要使用這樣一個(gè)約束叮叹,需要添加“隱式類型證明參數(shù)”:
class Pair[T](val first: T, val second: T)(implicit ev: T?<:<?Comparable[T])
不過在上面的例子中艾栋,使用類型約束并沒有比類型變量界定class Pair[T<:Comparable[T]]有更多的優(yōu)點(diǎn)。不過在某些場(chǎng)景下蛉顽,類型約束會(huì)很有用蝗砾。
類型約束讓你可以在泛型類中定義只能在特定條件下使用的方法,示例如下:
? class Pair[T](val first: T, val second: T) {
? ? def smaller(implicit ev: T <:< Comparable[T]) =
? ? ? if (first.compareTo(second) < 0) first else second
? }
? val p1 = new Pair("a", "b") //a
你可以構(gòu)造出Pair[File]携冤,盡管File并不是帶有先后次序的悼粮。只有當(dāng)你調(diào)用smaller方法的時(shí)候才會(huì)報(bào)錯(cuò)。
型變:協(xié)變和逆變
class Personclass Student extends Person
def?makeFriends(p:?Pair[Person]) //此函數(shù)要對(duì)Pair[Person]做某種處理曾棕,但是要調(diào)用Student里的方法
我們知道扣猫,因?yàn)殡m然Student是Person的子類,但是Pair[Student]和Pair[Person]一點(diǎn)關(guān)系都沒有翘地。如果你想要這樣的關(guān)系申尤,則必須在定義Pair類的時(shí)候表明這一點(diǎn):
class Pair[+T](val first: T, val second: T)// 可以協(xié)變,表明衙耕,可以用子類的方法
+號(hào)意味著如果Student是Person的子類昧穿,那么Pair[Student]也是Pair[Person]的子類。
也可以有另一個(gè)方向的型變橙喘∈蓖遥考慮泛型類型Friend[T],表示希望與類型T的人成為朋友的人:
? trait Friend[-T] {
? ? def befriend(someone: T)
? }
現(xiàn)在假定有一個(gè)函數(shù):
? def makeFriendWith(s: Student, f: Friend[Student]) {
? ? f.befriend(s)
? }
你能用Friend[Person]作為參數(shù)調(diào)用它嗎渴杆?也就是說寥枝,如果你有:
? class Person extends Friend[Person]
? class Student extends Person? val susan = new Student? val fred = new Person
函數(shù)調(diào)用makeFriendWith(susan,fred)能成功嗎宪塔?看上去應(yīng)該可以,因?yàn)閒red想和任何人叫交朋友囊拜,他也一定會(huì)和susan交朋友某筐。注意到這個(gè)時(shí)候,類型變化的方向和子類型方向是相反的冠跷。Student是Person的子類南誊,但是Friend[Student]是Friend[Person]的超類。這種情況下蜜托,需要將類型參數(shù)聲明為逆變的抄囚。
協(xié)變、逆變橄务,特質(zhì)的定義會(huì)使用到它
trait Function1 [-T1, +R] extends AnyRef