类型推断

本主题介绍 F# 编译器如何推断值、变量、参数和返回值的类型。

常规类型推理

类型推理的想法是,你不必指定 F# 构造的类型,除非编译器无法最终推断类型。 省略显式类型信息并不意味着 F# 是动态类型语言或 F# 中的值弱类型化。 F# 是一种静态类型化语言,这意味着编译器在编译期间推断出每个构造的确切类型。 如果编译器没有足够的信息来推断每个构造的类型,则必须提供其他类型信息,通常通过在代码中的某个位置添加显式类型注释。

参数和返回类型的推理

在参数列表中,无需指定每个参数的类型。 然而,F# 是一种静态类型化语言,因此每个值和表达式在编译时都有一个明确的类型。 对于未显式指定的类型,编译器会根据上下文推断类型。 如果未指定类型,则推断为泛型类型。 如果代码不一致地使用值,则编译器会报告错误,这样就没有满足值所有用途的单个推断类型。

函数的返回类型由函数中最后一个表达式的类型确定。

例如,在以下代码中,参数类型和ab返回类型都推断为int,因为文本100的类型int

let f a b = a + b + 100

可以通过更改文本来影响类型推理。 如果通过追加后缀u100uint32类型ab以及返回值进行推断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")

自动通用化

如果函数代码不依赖于参数的类型,编译器会将参数视为泛型。 这称为 自动通用化,它可以是编写泛型代码而无需增加复杂性的强大帮助。

例如,以下函数将任何类型的两个参数合并为元组。

let makeTuple a b = (a, b)

类型被推断为

'a -> 'b -> 'a * 'b

其他信息

F# 语言规范中更详细地描述了类型推理。

另请参阅