跳至內容
GitHub 儲存庫 論壇 RSS 新聞來源

型別推論(第一部分)

Brian J. Cardiff

型別推論是每位程式設計師都應該喜歡的功能。它讓程式設計師不必在程式碼中指定型別,而且非常方便。

在這裡,我們試圖解釋 Crystal 如何推斷程式型別的基礎。也旨在提供一些關於如何理解型別推論的文件。

像大多數型別推論演算法一樣,此解釋以抽象語法樹 (AST) 為指導。每個 AST 節點都將有一個相關的型別,對應於運算式的型別。

在進行型別推論時,會遍歷整個程式的 AST,以模擬程式設計師在發現型別時會做的推導。

字面值

這些都很容易。布林值、數字、字元和明確寫入的值的型別由語法直接確定。

true # : Boolean
1    # : Int32

變數

編譯器需要知道每個變數的型別。變數也有它們可以被求值的上下文。

型別推論演算法會在每個上下文中註冊存在的變數。因此,編譯器可以明確地宣告它們。

決定變數型別的最基本陳述是賦值。

v = true

賦值的 AST 節點有 1) 目標(左側),2) 運算式(右側)。當確定右側的型別時,型別推論演算法會聲明左側應能夠儲存該型別的值。

此演算法不是以回溯方式計算(為了支援更複雜的情況),而是透過在 AST 節點上建立依賴關係圖來運作。

下圖顯示 AST 節點、變數及其型別所在的上下文,以及藍色箭頭,強調各部分之間的型別依賴關係。

條件式(又名 If 語句)

Crystal 支援聯合型別。當在同一上下文(但在不同分支中)中多次賦值給變數時,它的預期型別是可以處理所有賦值的型別。因此,如果給定以下程式碼

if false
  v = false
else
  v = 2
end

在結束時,v 的型別應為 Int32 | Boolean

再次,我們顯示 AST 節點、變數及其型別所在的上下文,以及藍色箭頭,強調各部分之間的型別依賴關係。

當一個新型別到達上下文中的變數時,它會被新增到「正在進行」的已知型別中。因此,會出現聯合型別。

還有一件事尚未顯示。變數的每個出現都與上下文有依賴關係。這在下圖中顯示

這樣一來,每個賦值都知道它的目標是將 Boolean 賦值給 Int32 | BooleanInt32 賦值給 Int32 | Boolean。此資訊用於程式碼產生。