[譯] Scala 型別的型別(六)

ScalaCool發表於2017-07-22

上一篇

Scala 型別的型別(五)

目錄

26. 聯合型別

❌ 本部分尚未完成,但你可以通過 Miles 的部落格(下方有連結)獲得更多瞭解 :-)

讓我們開始來討論這個型別,這次要藉助下「集合論」,然後把我們已經學過的 A with B 當做一個「交集型別」。

為什麼呢?因為只有同時帶有型別 A 和型別 B 的物件才能符合這個型別,因此在集合論中,它將是一個交集。此外,我們思考下什麼是「聯合型別」。

這是兩個集合的聯合,逐集看每個元素的型別要麼是 A 或者 B。我們的任務是使用 Scala 型別系統來引入這樣的型別。雖然它們不是 Scala 中的第一等構造(不是內建的),我們也可以很容易地實現和使用它們。Miles Sabin 在部落格中通過「 Curry-Howard 同構」深入地解釋了這一技術,如果你比較好奇,可以去看看。

type |∨|[T, U] = { type λ[X] = ¬¬[X] <:< (TU) }

def size[T : (Int |∨| String)#λ](t : T) = t match {
    case i : Int => i
    case s : String => s.length
}複製程式碼

27. 延遲初始化

自從我們開始討論 Scala 中一些不常見的型別,我們就會安排專門的章節來介紹每一個型別。延遲初始化(Delayed Init)實際上只是一種編譯器的技巧而已,它對型別系統而言並不是非常重要。但是一旦你理解了它,就會明白 scala.App 是如何運作的,所以看看下面的例子吧:

object Main extends App {
  println("Hello world!")
}複製程式碼

檢視這段程式碼,根據我們已知的 Scala 基礎知識,會下這樣結論:「那麼,println 是在 Main 類的建構函式中!」。這通常是對的,但在這裡卻並不是這樣的,因為 App 繼承了 DelayedInit 特質:

trait App extends DelayedInit {
  // code here ...
}複製程式碼

讓我們來看看延遲初始化的特質的完整原始碼:

trait DelayedInit {
  def delayedInit(x: => Unit): Unit
}複製程式碼

正如你所見,它並沒有包含任何的實現 — 所有圍繞它的工作實際上都是編譯器執行的,它將以一種特殊的方式來對待「繼承了 DelayedInit」的類和單例(注:特質不會像這樣一樣重寫)。

特殊待遇是這樣子的:

  • 假設你的類/單例主體是一個函式,處理主體中要做的所有事情
  • 編譯器為你建立了這個函式,並將它傳遞給了延遲初始化方法(x: => Unit),

我們馬上來舉個例子,手動來重新實現一遍 App 為我們自動做的事情(在 delayedInit 的幫助下):

// we write:
object Main extends DelayedInit {
  println("hello!")
}

// the compiler emits:
object Main extends DelayedInit {
  def delayedInit(x: => Unit = { println("Hello!") }) = // impl is left for us to fill in
}複製程式碼

使用這種機制,你可以隨時執行你的類的主體。我們已經瞭解了延遲初始化如何工作,接下來再來實現下我們自己版本的 scala.App 吧(這實際上也是以相同方式實現的)。


  override def delayedInit(body: => Unit) {
    initCode += (() => body)
  }

  def main(args: Array[String]) = {
    println("Whoa, I'm a SimpleApp!")

    for (proc <- initCode) proc()

    println("So long and thanks for all the fish!")
  }
}

                                // Running the bellow class would print print:
object Test extends SimpleApp { //
                                // Whoa, I'm a SimpleApp!
  println("  Hello World!")     //   Hello World!
                                // So long and thanks for all the fish!
}複製程式碼

相關文章