Teilen über


Module

Im Kontext von F# ist ein Modul eine Gruppierung von F#-Code, z. B. Werte, Typen und Funktionswerte, in einem F#-Programm. Das Gruppieren von Code in Modulen trägt dazu bei, verwandten Code zusammenzuhalten und Namenskonflikte in Ihrem Programm zu vermeiden.

Syntax

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

Bemerkungen

Ein F#-Modul ist eine Gruppierung von F#-Codekonstrukten wie Typen, Werten, Funktionswerten und Code in do Bindungen. Sie wird als CLR-Klasse (Common Language Runtime) implementiert, die nur statische Member enthält. Es gibt zwei Typen von Moduldeklarationen, je nachdem, ob die gesamte Datei im Modul enthalten ist: eine Moduldeklaration auf oberster Ebene und eine lokale Moduldeklaration. Eine Moduldeklaration der obersten Ebene enthält die gesamte Datei im Modul. Eine Moduldeklaration der obersten Ebene kann nur als erste Deklaration in einer Datei angezeigt werden.

In der Syntax für die Moduldeklaration der obersten Ebene ist der optionale qualifizierte Namespace die Sequenz geschachtelter Namespacenamen, die das Modul enthalten. Der qualifizierte Namespace muss nicht zuvor deklariert werden.

In einem Modul der obersten Ebene müssen Sie keine Deklarationen einrücken. Sie müssen alle Deklarationen in lokalen Modulen einziehen. In einer lokalen Moduldeklaration sind nur die Deklarationen, die unter dieser Moduldeklaration eingezogen werden, Teil des Moduls.

Wenn eine Codedatei nicht mit einer Moduldeklaration der obersten Ebene oder einer Namespacedeklaration beginnt, wird der gesamte Inhalt der Datei, einschließlich aller lokalen Module, Teil eines implizit erstellten Moduls auf oberster Ebene, das denselben Namen wie die Datei hat, ohne die Erweiterung, mit dem ersten Buchstaben in Großbuchstaben konvertiert. Betrachten Sie beispielsweise die folgende Datei.

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

Diese Datei würde so kompiliert werden, als würde sie auf diese Weise geschrieben:

module Program
let x = 40

Wenn Sie über mehrere Module in einer Datei verfügen, müssen Sie für jedes Modul eine lokale Moduldeklaration verwenden. Wenn ein eingeschlossener Namespace deklariert wird, sind diese Module Teil des eingeschlossenen Namespace. Wenn kein eingeschlossener Namespace deklariert wird, werden die Module Teil des implizit erstellten Moduls auf oberster Ebene. Das folgende Codebeispiel zeigt eine Codedatei, die mehrere Module enthält. Der Compiler erstellt implizit ein Modul der obersten Ebene mit dem Namen Multiplemodulesund MyModule1MyModule2 wird in diesem Modul der obersten Ebene geschachtelt.

// 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)

Wenn Sie mehrere Dateien in einem Projekt oder in einer einzigen Kompilierung haben oder wenn Sie eine Bibliothek erstellen, müssen Sie oben in der Datei eine Namespacedeklaration oder Moduldeklaration einfügen. Der F#-Compiler bestimmt nur implizit einen Modulnamen, wenn nur eine Datei in einer Projekt- oder Kompilierungs-Befehlszeile vorhanden ist und Sie eine Anwendung erstellen.

Der Modifizierer für Barrierefreiheit kann eine der folgenden Sein: public, , privateinternal. Weitere Informationen finden Sie unter Access Control. Der Standardwert ist public.

Verweisen auf Code in Modulen

Wenn Sie auf Funktionen, Typen und Werte aus einem anderen Modul verweisen, müssen Sie entweder einen qualifizierten Namen verwenden oder das Modul öffnen. Wenn Sie einen qualifizierten Namen verwenden, müssen Sie die Namespaces, das Modul und den Bezeichner für das gewünschte Programmelement angeben. Sie trennen jeden Teil des qualifizierten Pfads wie folgt mit einem Punkt (.).

Namespace1.Namespace2.ModuleName.Identifier

Sie können das Modul oder mindestens einen der Namespaces öffnen, um den Code zu vereinfachen. Weitere Informationen zum Öffnen von Namespaces und Modulen finden Sie unter Importdeklarationen: Das open Schlüsselwort.

Das folgende Codebeispiel zeigt ein Modul der obersten Ebene, das den gesamten Code bis zum Ende der Datei enthält.

module Arithmetic

let add x y =
    x + y

let sub x y =
    x - y

Wenn Sie diesen Code aus einer anderen Datei im selben Projekt verwenden möchten, verwenden Sie entweder qualifizierte Namen, oder öffnen Sie das Modul, bevor Sie die Funktionen verwenden, wie in den folgenden Beispielen gezeigt.

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

Geschachtelte Module

Module können geschachtelt werden. Innere Module müssen so weit eingezogen werden, dass es sich um äußere Moduldeklarationen handelt, um anzugeben, dass es sich um innere Module und nicht um neue Module handelt. Vergleichen Sie beispielsweise die folgenden beiden Beispiele. Modul Z ist ein inneres Modul im folgenden Code.

module Y =
    let x = 1

    module Z =
        let z = 5

Modul ist jedoch ein gleichgeordnetes Modul Z im Y folgenden Code.

module Y =
    let x = 1

module Z =
    let z = 5

Modul Z ist auch ein gleichgeordnetes Modul im folgenden Code, da es nicht so weit wie andere Deklarationen im Modul Yeingezogen wird.

module Y =
        let x = 1

    module Z =
        let z = 5

Wenn das äußere Modul keine Deklarationen aufweist und unmittelbar von einer anderen Moduldeklaration gefolgt wird, wird davon ausgegangen, dass die neue Moduldeklaration ein inneres Modul ist. Der Compiler warnt Sie jedoch, wenn die zweite Moduldefinition nicht weiter als die erste eingezogen wird.

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

Um die Warnung zu beseitigen, fangen Sie das innere Modul ein.

module Y =
    module Z =
        let z = 5

Wenn sich der gesamte Code in einer Datei in einem einzigen äußeren Modul befinden soll und sie innere Module benötigen, benötigt das äußere Modul nicht das Gleichheitszeichen, und die Deklarationen, einschließlich aller inneren Moduldeklarationen, die im äußeren Modul erfolgen, müssen nicht eingezogen werden. Deklarationen innerhalb der inneren Moduldeklarationen müssen eingezogen werden. Der folgende Code zeigt diesen Fall.

// 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

Rekursive Module

F# 4.1 führt den Begriff der Module ein, die es ermöglichen, dass sich alle enthaltenen Code gegenseitig rekursiv verhalten. Dies erfolgt über module rec. module rec Die Verwendung kann einige Schmerzen lindern, die nicht in der Lage sind, sich gegenseitig referenzieller Code zwischen Typen und Modulen zu schreiben. Im Folgenden sehen Sie ein Beispiel dafür:

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

Beachten Sie, dass die Ausnahme DontSqueezeTheBananaException und die Klasse Banana beide miteinander verweisen. Darüber hinaus beziehen sich das Modul BananaHelpers und die Klasse Banana auch aufeinander. Dies wäre nicht möglich, in F# auszudrücken, wenn Sie das rec Schlüsselwort aus dem RecursiveModule Modul entfernt haben.

Diese Funktion ist auch in Namespaces mit F# 4.1 möglich.

Siehe auch