共用方式為


模組

在 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 類型、值、函式值和程式代碼。 它實作為只有靜態成員的 Common Language Runtime (CLR) 類別。 模組宣告有兩種類型,取決於整個檔案是否包含在模組中:最上層模組宣告和本機模組宣告。 最上層模組宣告包含模組中的整個檔案。 最上層模組宣告只能顯示為檔案中的第一個宣告。

在最上層模組宣告的語法中,選擇性 限定命名空間 是包含模組的巢狀命名空間名稱序列。 限定的命名空間不需要先前宣告。

您不需要在最上層模組中縮排宣告。 您必須縮排本機模組中的所有宣告。 在本機模組宣告中,只有縮排在該模組宣告底下的宣告是模組的一部分。

如果程式代碼檔案不是以最上層模組宣告或命名空間宣告開頭,則檔案的完整內容,包括任何本機模組,都會成為隱含建立的最上層模組的一部分,該模組的名稱與檔案同名,不含擴展名,且第一個字母轉換成大寫。 例如,請考慮下列檔案。

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

此檔案的編譯方式會如同以這種方式撰寫:

module Program
let x = 40

如果您在檔案中有多個模組,則必須針對每個模組使用本機模組宣告。 如果宣告封入命名空間,這些模組是封入命名空間的一部分。 如果未宣告封入命名空間,模組會成為隱含建立的最上層模組的一部分。 下列程式代碼範例顯示包含多個模組的程式代碼檔案。 編譯程式會隱含地建立名為 Multiplemodules的頂層模組,且 MyModule1MyModule2 會巢狀在該最上層模組中。

// 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# 編譯程式只會隱含判斷模組名稱。

輔助功能修飾詞可以是下列其中一項:publicprivateinternal。 如需詳細資訊,請參閱 存取控制。 預設值是公用。

參考模組中的程序代碼

當您參考來自另一個模組的函式、類型和值時,您必須使用限定名稱或開啟模組。 如果您使用限定名稱,則必須指定您想要之程式專案的命名空間、模組和識別碼。 您可以使用點 (.) 分隔限定路徑的每個部分,如下所示。

Namespace1.Namespace2.ModuleName.Identifier

您可以開啟模組或一或多個命名空間,以簡化程序代碼。 如需開啟命名空間和模組的詳細資訊,請參閱 匯入宣告: open 關鍵詞

下列程式代碼範例顯示最上層模組,其中包含檔案結尾的所有程序代碼。

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

但module Z 是下列程式代碼中模組 Y 的同層級。

module Y =
    let x = 1

module Z =
    let z = 5

Module 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# 4.1 引進模組的概念,可讓所有自主程式代碼相互遞歸。 這是透過 module rec來完成。 module rec使用 可減輕無法撰寫類型與模組之間相互引用程式代碼的一些痛苦。 以下是下列範例:

module rec RecursiveModule =
    type Orientation = Up | Down
    type PeelState = Peeled | Unpeeled

    // This exception depends on the type below.
    exception DontSqueezeTheBananaException of Banana

    type Banana(orientation : Orientation) =
        member val Orientation = orientation with get, set
        member val Sides: PeelState list = [ Unpeeled; Unpeeled; Unpeeled; Unpeeled ] with get, set

        member self.IsPeeled =
            self.Sides |> List.forall ((=) Peeled)

        member self.Peel() =
            BananaHelpers.peel self
            |> fun peeledSides -> self.Sides <- peeledSides

        member self.SqueezeJuiceOut() =
            raise (DontSqueezeTheBananaException self)

    module BananaHelpers =
        let peel (banana: Banana) =
            let flip (banana: Banana) =
                match banana.Orientation with
                | Up ->
                    banana.Orientation <- Down
                    banana
                | Down -> banana

            let peelSides (banana: Banana) =
                banana.Sides
                |> List.map (function
                             | Unpeeled -> Peeled
                             | Peeled -> Peeled)

            banana |> flip |> peelSides

請注意,例外狀況 DontSqueezeTheBananaException 和 類別 Banana 都彼此參考。 此外,模組 BananaHelpers 和類別 Banana 也會彼此參考。 如果您從RecursiveModule模組中移除 rec 關鍵詞,則無法在 F# 中表示。

在具有 F# 4.1 的命名空間 中,也可以使用這項功能。

另請參閱