在 Scala 中所有值都有一種對應的型別
單例型別
-
形式:
value.type,回傳型別value/null -
場景1:鏈式API呼叫時的型別指定
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實體作為引數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 -
場景:內部類使用時避免型別約束
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內部 -
好處: 在參考型別時可以更加簡潔
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方法的實體作為引數傳入,由于反射的代價較大,不到萬不得已不建議使用,如,有通用行為(
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的操作
中綴型別名稱可以是任意運算子,除了
*,避免與型別定義沖突
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/1989.html
標籤:Scala
