型別推論(第一部分)
型別推論是每位程式設計師都應該喜歡的功能。它讓程式設計師不必在程式碼中指定型別,而且非常方便。
在這裡,我們試圖解釋 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 | Boolean
或 Int32
賦值給 Int32 | Boolean
。此資訊用於程式碼產生。