在 Scala 中所有值都有一種對(duì)應(yīng)的類型
單例類型
形式:
value.type
,返回類型value
/null
-
場(chǎng)景1:鏈?zhǔn)紸PI調(diào)用時(shí)的類型指定
class Super { def m1(t: Int) = {println(t); this} def m2(t: Int) = {println(t); this} } // 正常打印 new Super().m1(1).m2(2) class Child extends Super { def c1(t: Int) = {println(t); this} } // 異常 value c1 is not a member of Super new Child().m1(1).c1(2)
由于 Scala 會(huì)將
this
推斷為當(dāng)前類(即Super
)糠雨,因此無法完成鏈?zhǔn)秸{(diào)用class Super { // 指定返回類型為調(diào)用方的 this def m1(t: Int): this.type = {println(t); this} def m2(t: Int): this.type = {println(t); this} } class Child extends Super { def c1(t: Int) = {println(t); this} } // 成功打印 new Child().m1(1).c1(2)
-
場(chǎng)景2:方法中使用
object
實(shí)例作為參數(shù)object Foo class Child extends Super { def c1(obj: Foo.type) = { if (obj == Foo) println("foo") this } }
Note:不可定義為
def c1(obj: Foo)祥楣,因?yàn)?Foo 為單例對(duì)象娜睛,而不是類型
類型投影
形式:
Outer#Inner
-
場(chǎng)景:內(nèi)部類使用時(shí)避免類型約束
class Outer { private val inners = ArrayBuffer[Inner]() class Inner (val arg1: Int) { val l = ArrayBuffer[Inner]() } def add(a: Int) = { val t = new Inner(a) inners += t t } } val a = new Outer val b = new Outer val a1 = a.add(1) val b1 = b.add(1) a1.l += b1 // error: type mismatch;
只需要在定義內(nèi)部類時(shí)指定類型投影即可解決
// 表示適用于任何 Outer 類的 Inner 類 val l = ArrayBuffer[Outer#Inner]()
如果將上述例子改用
List
來實(shí)現(xiàn)鼓拧,并不會(huì)報(bào)錯(cuò)谍倦,計(jì)算結(jié)果也會(huì)自動(dòng)進(jìn)行類型投射
路徑
路徑中除最后一部分外耍铜,都必須是穩(wěn)定狀態(tài)的邑闺,如包名、
object
业扒、val
检吆、this/super/super[S]...
-
不能包含
var
類型var t = new Outer() //...其他操作 val i = new t.Inner // 由于 t 可能會(huì)變更舒萎,編譯器無法確定其含義
a.b.c.T 內(nèi)部被翻譯成類型投射 a.b.c.type#T
類型別名
形式:
type SomeAliasName
必須定義在
class
或object
內(nèi)部-
好處: 在引用類型時(shí)可以更加簡(jiǎn)潔
class Book { import scala.collection.mutable._ // 為該類型取一個(gè)別名 type Index = HashMap[String, Int] // 使用時(shí)不在需要重復(fù)的定義復(fù)雜的數(shù)據(jù)類型 val map: Index = new Index() } new Book().map // scala.collection.mutable.HashMap[String,Int]
結(jié)構(gòu)類型
-
為抽象方法程储、字段蹭沛、類型的定義某種規(guī)范
def appendLines(target: { def append(str: String): Any }, lines: Iterable[String]) { for (l <- lines) { // 此次 Scala 使用反射調(diào)用該方法 target.append(l); target.append("\n") } }
該方法第一個(gè)參數(shù)
target
即結(jié)構(gòu)類型,表示使用任何包含該append
方法的實(shí)例作為參數(shù)傳入章鲤。由于反射的代價(jià)較大摊灭,不到萬不得已不建議使用,如败徊,有通用行為(
append
)帚呼,卻無法共享trait
組合類型 / 交集類型
形式:
T1 with T2 with T3 ...
-
當(dāng)需要提供多個(gè)特質(zhì)時(shí)使用,即用于約束類型
val image = new ArrayBuffer[java.awt.Shape with java.io.Serializable] val rect = new Rectangle(5, 10, 20, 30) image += rect // 正確皱蹦,Rectangle 可序列化 image += new Area(rect) // 錯(cuò)誤 Area 不可序列化
-
組合類型中也可使用結(jié)構(gòu)類型
Shape with Serializable { def contains(p: Point): Boolean }
中綴類型
其實(shí)只是一種語法寫法煤杀,如
String Map Int
可代替Map[String, Int]
-
可參考數(shù)學(xué)運(yùn)算中的表達(dá)方式
type x[A, B] = (String, Int) // 即可使用 String x Int 來表示 (String, Int)
一般中綴類型操作符都是左關(guān)聯(lián)的,除了前面提到的
:
操作符沪哺,這個(gè)是右關(guān)聯(lián)的沈自,比如List
的操作
中綴類型名稱可以是任意操作符,除了
*
辜妓,避免與類型定義沖突