型別推斷 (F#)
本主題描述 F# 編譯器如何推斷值、變數、參數和傳回值的型別。
一般型別推斷
型別推斷的概念是,除非編譯器無法確定推算型別,否則您不需要指定 F# 建構的型別。 省略明確型別資訊不代表 F# 是動態型別語言或者 F# 中的值是弱式型別。 F# 是靜態型別語言,表示編譯器會在編譯期間推算每個建構的確切型別。 如果因為資訊不足導致編譯器無法推算每個建構的型別,您必須提供其他型別資訊 (通常是在程式碼的某個位置加入明確型別附註)。
參數型別和傳回型別推斷
您不需要在參數清單中指定每個參數的型別。 由於 F# 是靜態型別語言,因此在編譯時期每個值和運算式都有明確型別。 對於未明確指定的型別,編譯器會根據內容推斷型別。 如果是未另行指定的型別,就會推斷為泛型。 如果以不一致的方式在程式碼中使用某個值,會導致沒有單一推斷的型別可以滿足值的所有使用情形,編譯器就會報告錯誤。
函式的傳回型別是由函式中最後一個運算式的型別決定。
例如,在下列程式碼中,參數型別 a 和 b 以及傳回型別經推斷都是 int,因為常值 100 屬於 int 型別。
let f a b = a + b + 100
您可以透過變更常值來影響型別推斷。 如果透過附加後置字元 u,讓 100 成為 uint32,則 a 和 b 的型別以及傳回型別都會推斷為 uint32。
您也可以使用其他代表限制型別的建構來影響型別推斷,例如只用於特定型別的函式和方法。
此外,您還可以將明確型別附註套用至函式或方法參數,或者套用至運算式中的變數,如下列範例所示。 如果不同的條件約束之間發生衝突,則會產生錯誤。
// Type annotations on a parameter.
let addu1 (x : uint32) y =
x + y
// Type annotations on an expression.
let addu2 x y =
(x : uint32) + y
您也可以在所有參數後面提供型別附註,明確指定函式的傳回值。
let addu1 x y : uint32 =
x + y
型別附註適用於參數的常見情況是參數為物件型別且您想要使用成員時。
let replace(str: string) =
str.Replace("A", "a")
自動一般化
如果函式程式碼不相依於參數的型別,編譯器會將參數視為泛型。 這稱為「自動一般化」(Automatic Generalization),是撰寫泛型程式碼而不增加複雜度的強大輔助功能。
例如,下列函式會將任何型別的兩個參數結合為 Tuple。
let makeTuple a b = (a, b)
型別經推斷為
'a -> 'b -> 'a * 'b
其他資訊
以 F# 語言規格詳細說明型別推斷。