let 绑定
绑定可将标识符与值或函数相关联。 let
关键字用于将名称绑定到值或函数。
语法
// Binding a value:
let identifier-or-pattern [: type] =expressionbody-expression
// Binding a function value:
let identifier parameter-list [: return-type ] =expressionbody-expression
备注
let
关键字在绑定表达式中用于定义一个或多个名称的值或函数值。 let
表达式的最简单形式可将名称绑定到简单值,如下所示。
let i = 1
如果使用新行将表达式与标识符隔开,则必须缩进表达式的每一行,如以下代码所示。
let someVeryLongIdentifier =
// Note indentation below.
3 * 4 + 5 * 6
除了名称之外,还可以指定包含名称的模式(例如元组),如以下代码所示。
let i, j, k = (1, 2, 3)
body-expression 是使用名称的表达式。 主体表达式单独占用一行,缩进为与 let
关键字中的第一个字符完全对齐:
let result =
let i, j, k = (1, 2, 3)
// Body expression:
i + 2 * j + 3 * k
let
绑定可以出现在模块级别、类类型的定义中或本地范围内,例如在函数定义中。 模块或类类型顶层的 let
绑定不需要有主体表达式,但在其他范围级别需要有主体表达式。 绑定名称可在定义点后使用,但在 let
绑定出现之前的任何时候都不能使用,如以下代码所示。
// Error:
printfn "%d" x
let x = 100
// OK:
printfn "%d" x
函数绑定
函数绑定遵循值绑定规则,只不过函数绑定包括函数名称和参数,如以下代码所示。
let function1 a = a + 1
通常,参数是模式,如元组模式:
let function2 (a, b) = a + b
let
绑定表达式的计算结果为最后一个表达式的值。 因此,在以下代码示例中,result
的值是从 100 * function3 (1, 2)
计算得出的,其计算结果为 300
。
let result =
let function3 (a, b) = a + b
100 * function3 (1, 2)
有关详细信息,请参阅函数。
类型注释
你可以通过包含冒号 (:) 后跟类型名称来指定参数的类型,所有这些内容都括在括号中。 你还可以通过在最后一个参数后面追加冒号和类型来指定返回值的类型。 function1
的完整类型注释(以整数作为参数类型)如下所示。
let function1 (a: int) : int = a + 1
如果没有显式类型参数,则使用类型推理来确定函数的参数类型。 这可能包括自动将参数类型泛化为泛型。
类中的 let 绑定
let
绑定可以出现在类类型中,但不能出现在结构或记录类型中。 若要在类类型中使用 let 绑定,该类必须具有主构造函数。 构造函数参数必须出现在类定义中的类型名称后面。 类类型中的 let
绑定定义该类类型的私有字段和成员,并与类型中的 do
绑定一起构成类型主构造函数的代码。 以下代码示例展示了具有私有字段 field1
和 field2
的类 MyClass
。
type MyClass(a) =
let field1 = a
let field2 = "text"
do printfn "%d %s" field1 field2
member this.F input =
printfn "Field1 %d Field2 %s Input %A" field1 field2 input
field1
和 field2
的范围仅限于声明它们的类型。 有关详细信息,请参阅类中的 let
绑定和类。
let 绑定中的类型参数
模块级别、类型或计算表达式中的 let
绑定可以具有显式类型参数。 表达式(例如函数定义)中的 let 绑定不能有类型参数。 有关详细信息,请参阅泛型。
let 绑定上的属性
可以向模块中的顶级 let
绑定应用属性,如以下代码所示。
[<Obsolete>]
let function1 x y = x + y
let 绑定的范围和可访问性
使用 let 绑定声明的实体的范围仅限于绑定出现后包含范围的部分(例如函数、模块、文件或类)。 因此,可以说,let 绑定将名称引入范围。 在模块中,只要模块可供访问,模块的客户端就可以访问 let 绑定值或函数,因为模块中的 let 绑定编译为模块的公共函数。 相比之下,类中的 let 绑定是类私有的。
通常,客户端代码使用模块中的函数时,函数必须由模块名称限定。 例如,如果模块 Module1
具有函数 function1
,用户将指定 Module1.function1
来引用该函数。
模块用户可以使用导入声明使该模块中的函数可供使用,而无需由模块名称限定。 在刚才提到的示例中,模块用户在这种情况下可以通过使用导入声明 open Module1
打开模块,然后直接引用 function1
。
module Module1 =
let function1 x = x + 1.0
module Module2 =
let function2 x =
Module1.function1 x
open Module1
let function3 x =
function1 x
某些模块具有属性 RequireQualifiedAccess,这意味着它们公开的函数必须使用模块名称进行限定。 例如,F# List 模块具有此属性。