類型推斷
本主題說明 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")
自動一般化
如果函式程式碼不需依賴參數的型別,編譯器會將參數視為泛型。 這稱為「自動一般化」,如果想在撰寫泛型程式碼時不要增加複雜度,這種特性非常有幫助。
舉例來說,下列函式會將任何型別的兩個參數合併成 Tuple。
let makeTuple a b = (a, b)
型別推斷為
'a -> 'b -> 'a * 'b
其他資訊
F# 語言規格會更詳細說明型別推斷。