在 Scala 中全部值都有一種對應的類型java
value.type
,返回類型 value
/ null
場景1:鏈式API調用時的類型指定app
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 會將this
推斷爲當前類(即Super
),所以沒法完成鏈式調用
class Super { // 指定返回類型爲調用方的 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)
場景2:方法中使用 object
實例做爲參數this
object Foo class Child extends Super { def c1(obj: Foo.type) = { if (obj == Foo) println("foo") this } }
Note:不可定義爲def c1(obj: Foo),由於 Foo 爲單例對象,而不是類型
Outer#Inner
場景:內部類使用時避免類型約束scala
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;
只須要在定義內部類時指定類型投影便可解決
// 表示適用於任何 Outer 類的 Inner 類 val l = ArrayBuffer[Outer#Inner]()
若是將上述例子改用
List
來實現,並不會報錯,計算結果也會自動進行類型投射
object
、val
、this/super/super[S]...
不能包含 var
類型翻譯
var t = new Outer() //...其餘操做 val i = new t.Inner // 因爲 t 可能會變動,編譯器沒法肯定其含義
a.b.c.T 內部被翻譯成類型投射 a.b.c.type#T
type SomeAliasName
class
或 object
內部好處: 在引用類型時能夠更加簡潔code
class Book { import scala.collection.mutable._ // 爲該類型取一個別名 type Index = HashMap[String, Int] // 使用時不在須要重複的定義複雜的數據類型 val map: Index = new Index() } new Book().map // scala.collection.mutable.HashMap[String,Int]
爲抽象方法、字段、類型的定義某種規範對象
def appendLines(target: { def append(str: String): Any }, lines: Iterable[String]) { for (l <- lines) { // 這次 Scala 使用反射調用該方法 target.append(l); target.append("\n") } }
該方法第一個參數 target
即結構類型,表示使用任何包含該 append
方法的實例做爲參數傳入。get
因爲反射的代價較大,不到萬不得已不建議使用,如,有通用行爲(append
),卻沒法共享trait
T1 with T2 with T3 ...
當須要提供多個特質時使用,即用於約束類型編譯器
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) // 錯誤 Area 不可序列化
組合類型中也可以使用結構類型數學
Shape with Serializable { def contains(p: Point): Boolean }
String Map Int
可代替 Map[String, Int]
可參考數學運算中的表達方式
type x[A, B] = (String, Int) // 便可使用 String x Int 來表示 (String, Int)
:
操做符,這個是右關聯的,好比 List
的操做
中綴類型名稱能夠是任意操做符,除了
*
,避免與類型定義衝突