Namespaces (F#)
Mit einem Namespace können Sie Code in Bereichen verwandter Funktionalität organisieren, indem Sie einen Namen an eine Gruppierung von F#-Programmelementen anfügen. Namespaces sind in der Regel Elemente der obersten Ebene in F#-Dateien.
Syntax
namespace [rec] [parent-namespaces.]identifier
Bemerkungen
Wenn Sie Code in einen Namespace einfügen möchten, muss die erste Deklaration in der Datei den Namespace deklarieren. Der Inhalt der gesamten Datei wird dann Teil des Namespace, sofern keine andere Namespacedeklaration in der Datei vorhanden ist. In diesem Fall wird davon ausgegangen, dass der gesamte Code bis zur nächsten Namespacedeklaration im ersten Namespace enthalten ist.
Namespaces können nicht direkt Werte und Funktionen enthalten. Stattdessen müssen Werte und Funktionen in Modulen enthalten sein, und Module sind in Namespaces enthalten. Namespaces können Typen und Module enthalten.
XML-Dokumentationskommentare können über einem Namespace deklariert werden, werden aber ignoriert. Compileranweisungen können auch über einem Namespace deklariert werden.
Namespaces können explizit mit dem namespace-Schlüsselwort oder implizit beim Deklarieren eines Moduls deklariert werden. Verwenden Sie zum expliziten Deklarieren eines Namespace das namespace-Schlüsselwort gefolgt vom Namespacenamen. Das folgende Beispiel zeigt eine Codedatei, die den Namespace Widgets
mit einem Typ und einem Modul in diesem Namespace deklariert.
namespace Widgets
type MyWidget1 =
member this.WidgetName = "Widget1"
module WidgetsModule =
let widgetName = "Widget2"
Wenn sich der gesamte Inhalt der Datei in einem Modul befindet, können Sie Namespaces auch implizit deklarieren, indem Sie das Schlüsselwort module
verwenden und den neuen Namespacenamen im vollqualifizierten Modulnamen angeben. Das folgende Beispiel zeigt eine Codedatei, die den Namespace Widgets
und das Modul WidgetsModule
deklariert, das eine Funktion enthält.
module Widgets.WidgetModule
let widgetFunction x y =
printfn "%A %A" x y
Der folgende Code entspricht dem vorherigen Code, aber das Modul ist eine lokale Moduldeklaration. In diesem Fall muss der Namespace in einer eigenen Zeile angegeben werden.
namespace Widgets
module WidgetModule =
let widgetFunction x y =
printfn "%A %A" x y
Wenn mehrere Module in derselben Datei in einem oder mehreren Namespaces erforderlich sind, müssen Sie lokale Moduldeklarationen verwenden. Wenn Sie lokale Moduldeklarationen verwenden, können Sie den qualifizierten Namespace nicht in den Moduldeklarationen verwenden. Der folgende Code zeigt eine Datei mit einer Namespacedeklaration und zwei lokalen Moduldeklarationen. In diesem Fall sind die Module direkt im Namespace enthalten. Es gibt kein implizit erstelltes Modul, das denselben Namen wie die Datei hat. Jeder andere Code in der Datei, z. B. eine do
-Bindung, befindet sich im Namespace, aber nicht in den inneren Modulen. Daher müssen Sie den Modulmember widgetFunction
mithilfe des Modulnamens qualifizieren.
namespace Widgets
module WidgetModule1 =
let widgetFunction x y =
printfn "Module1 %A %A" x y
module WidgetModule2 =
let widgetFunction x y =
printfn "Module2 %A %A" x y
module useWidgets =
do
WidgetModule1.widgetFunction 10 20
WidgetModule2.widgetFunction 5 6
Die Ausgabe dieses Beispiels sieht folgendermaßen aus:
Module1 10 20
Module2 5 6
Weitere Informationen finden Sie unter Module.
Geschachtelte Namespaces
Wenn Sie einen geschachtelten Namespace erstellen, müssen Sie ihn vollständig qualifizieren. Andernfalls erstellen Sie einen neuen Namespace der obersten Ebene. Der Einzug wird in Namespacedeklarationen ignoriert.
Im folgenden Beispiel wird das Deklarieren eines geschachtelten Namespace veranschaulicht:
namespace Outer
// Full name: Outer.MyClass
type MyClass() =
member this.X(x) = x + 1
// Fully qualify any nested namespaces.
namespace Outer.Inner
// Full name: Outer.Inner.MyClass
type MyClass() =
member this.Prop1 = "X"
Namespaces in Dateien und Assemblys
Namespaces können mehrere Dateien in einem einzelnen Projekt oder einer einzelnen Kompilierung umfassen. Der Begriff Namespacefragment beschreibt den Teil eines Namespace, der in einer Datei enthalten ist. Namespaces können auch mehrere Assemblys umfassen. Beispielsweise umfasst der Namespace System
die gesamte .NET Framework-Instanz, die viele Assemblys umfasst und zahlreiche geschachtelte Namespaces enthält.
Namespace „global“
Sie verwenden den vordefinierten Namespace global
, um Namen im .NET-Namespace der obersten Ebene zu platzieren.
namespace global
type SomeType() =
member this.SomeMember = 0
Sie können „global“ auch verwenden, um auf den .NET-Namespace der obersten Ebene zu verweisen, z. B. zum Auflösen von Namenskonflikten mit anderen Namespaces.
global.System.Console.WriteLine("Hello World!")
Rekursive Namespaces
Namespaces können auch als rekursiv deklariert werden, damit der gesamte enthaltene Code wechselseitig rekursiv ist. Dies erfolgt über namespace rec
. Durch die Verwendung von namespace rec
können einige Probleme umgangen werden, die dadurch entstehen, dass kein gegenseitig referenzieller Code zwischen Typen und Modulen geschrieben werden kann. Im Folgenden sehen Sie ein Beispiel dafür:
namespace rec MutualReferences
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 IsPeeled = false with get, set
member val Orientation = orientation with get, set
member val Sides: PeelState list = [ Unpeeled; Unpeeled; Unpeeled; Unpeeled] with get, set
member self.Peel() = BananaHelpers.peel self // Note the dependency on the BananaHelpers module.
member self.SqueezeJuiceOut() = raise (DontSqueezeTheBananaException self) // This member depends on the exception above.
module BananaHelpers =
let peel (b: 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)
match b.Orientation with
| Up -> b |> flip |> peelSides
| Down -> b |> peelSides
Beachten Sie, dass die Ausnahme DontSqueezeTheBananaException
und die Klasse Banana
aufeinander verweisen. Darüber hinaus verweisen auch das Modul BananaHelpers
und die Klasse Banana
aufeinander. Es ist nicht möglich, dies in F# auszudrücken, wenn Sie das Schlüsselwort rec
aus dem Namespace MutualReferences
entfernen.
Dieses Feature ist auch für Module der obersten Ebene verfügbar.
Weitere Informationen
- F#-Sprachreferenz
- Module
- F# RFC FS-1009 - Allow mutually referential types and modules over larger scopes within files (F# RFC FS-1009: Zulassen von gegenseitig referenziellen Typen und Modulen in großen Bereichen innerhalb von Dateien)