模块 (F#)

对于 F# 语言而言,模块是指 F# 代码的分组。例如,F# 程序中的值、类型和函数值。 通过将代码分组到各个模块中,可有助于将相关的代码放置在一起,并避免程序中出现名称冲突。

// Top-level module declaration. 
module [accessibility-modifier] [qualified-namespace.]module-name
declarations
// Local module declaration.
module [accessibility-modifier] module-name =
   declarations

备注

F# 模块是 F# 代码构造的分组,例如,类型、值、函数值以及 do 绑定中的代码。 模块可以作为只包含静态成员的公共语言运行时 (CLR) 类实现。 根据模块中是否包括整个文件,有两种类型的模块声明:顶级模块声明和局部模块声明。 顶级模块声明会将整个文件包括在模块中。 顶级模块声明只能作为文件中的第一个声明出现。

在顶级模块声明的语法中,可选的 qualified-namespace 是包含模块的嵌套命名空间名称的序列。 不必提前声明限定的命名空间。

不必缩进顶级模块中的声明, 但必须缩进局部模块中的所有声明。 在一个局部模块声明中,只有缩进到该模块声明之下的声明才属于模块的一部分。

如果某个代码文件不以顶级模块声明或命名空间声明开头,则该文件的全部内容(包括任何局部模块)将成为隐式创建的顶级模块的一部分。隐式创建的顶级模块的名称与该文件的名称相同,但不带扩展名,且首字母会转换为大写字母。 以下面的文件为例。

// In the file program.fs.
let x = 40

将此文件按照如同按以下方式编写的一样来进行编译:

module Program
let x = 40

如果一个文件中存在多个模块,则必须为每个模块使用局部模块声明。 如果声明一个封闭命名空间,则这些模块将属于该封闭命名空间的一部分。 如果不声明封闭命名空间,则这些模块将成为隐式创建的顶级模块的一部分。 下面的代码示例演示一个包含多个模块的代码文件。 编译器将隐式地创建一个名为 Multiplemodules 的顶级模块,而 MyModule1 和 MyModule2 则嵌套在该顶级模块中。

// In the file multiplemodules.fs.
// MyModule1
module MyModule1 =
    // Indent all program elements within modules that are declared with an equal sign.
    let module1Value = 100

    let module1Function x =
        x + 10

// MyModule2
module MyModule2 =

    let module2Value = 121

    // Use a qualified name to access the function.
    // from MyModule1.
    let module2Function x =
        x * (MyModule1.module1Function module2Value)

如果项目中或单个编译中有多个文件,或者您正在生成一个库,则必须在文件顶部包含命名空间声明或模块声明。 如果项目或编译命令行中只有一个文件,并且您正在创建应用程序,则 F# 编译器只能隐式确定模块名称。

accessibility-modifier 可以是以下值之一:public、private 和 internal。 有关更多信息,请参见访问控制 (F#)。 默认为公共。

引用模块中的代码

当从另一个模块引用函数、类型和值时,您必须使用限定名称或打开相应模块。 如果使用限定名称,则必须为需要的程序元素指定命名空间、模块和标识符。 限定路径的每部分用句点 (.) 隔开,如下所示。

Namespace1.Namespace2.ModuleName.Identifier

可以打开相应模块或一个或多个命名空间以简化代码。 有关打开命名空间和模块的更多信息,请参见导入声明:open 关键字 (F#)

下面的代码示例演示包含直到文件结尾的所有代码的顶级模块。

module Arithmetic

let add x y =
    x + y

let sub x y =
    x - y

若要从同一个项目中的另一个文件使用此代码,您可以使用限定名称,也可以先打开该模块,然后使用这两个函数,如以下示例中所示。

// Fully qualify the function name.
let result1 = Arithmetic.add 5 9
// Open the module.
open Arithmetic
let result2 = add 5 9

嵌套模块

模块可以嵌套。 内部模块必须相对于外部模块声明进行缩进,以指示这些模块是内部模块,而非新模块。 例如,让我们对下面的两个示例进行一下比较。 以下代码中的模块 Z 是一个内部模块。

module Y =
    let x = 1 

    module Z =
        let z = 5

但在下面的代码中,模块 Z 和模块 Y 是同级模块。

module Y =
    let x = 1 

module Z =
    let z = 5

以下代码中的模块 Z 也是同级模块,因为它没有相对于模块 Y 中的其他声明进行缩进。

module Y =
        let x = 1

    module Z =
        let z = 5

最后,如果外部模块不包含任何声明并且后面紧跟另一个模块声明,则认为新的模块声明是内部模块;但是,如果第二个模块定义没有相对于第一个模块进行缩进,则编译器将向您发出警告。

// This code produces a warning, but treats Z as a inner module.
module Y =
module Z =
    let z = 5

若要消除警告,请缩进内部模块。

module Y =
    module Z =
        let z = 5

如果您要将一个文件中的所有代码包含在单个外部模块中,并且还需要使用内部模块,则外部模块不要求等号,而且将进入外部模块的声明(包括任何内部模块声明)不必进行缩进。 但是,内部模块声明内部的声明必须进行缩进。 下面的代码演示了这一情况。

// The top-level module declaration can be omitted if the file is named
// TopLevel.fs or topLevel.fs, and the file is the only file in an
// application.
module TopLevel

let topLevelX = 5

module Inner1 =
    let inner1X = 1
module Inner2 =
    let inner2X = 5

请参见

参考

命名空间 (F#)

其他资源

F# 语言参考