Namnområden (F#)
Med ett namnområde kan du ordna kod i områden med relaterade funktioner genom att koppla ett namn till en gruppering av F#-programelement. Namnområden är vanligtvis element på den översta nivån i F#-filer.
Syntax
namespace [rec] [parent-namespaces.]identifier
Kommentarer
Om du vill placera kod i ett namnområde måste den första deklarationen i filen deklarera namnområdet. Innehållet i hela filen blir sedan en del av namnområdet, förutsatt att det inte finns någon annan namnområdesdeklaration längre i filen. Om så är fallet anses all kod fram till nästa namnområdesdeklaration vara inom förnamnområdet.
Namnområden får inte innehålla värden och funktioner direkt. I stället måste värden och funktioner ingå i moduler, och moduler ingår i namnområden. Namnområden kan innehålla typer och moduler.
XML-dokumentkommentorer kan deklareras ovanför ett namnområde, men de ignoreras. Kompilatordirektiv kan också deklareras ovanför ett namnområde.
Namnområden kan deklareras explicit med nyckelordet för namnområdet, eller implicit när du deklarerar en modul. Om du vill deklarera ett namnområde explicit använder du nyckelordet för namnområdet följt av namnområdesnamnet. I följande exempel visas en kodfil som deklarerar ett namnområde Widgets
med en typ och en modul som ingår i namnområdet.
namespace Widgets
type MyWidget1 =
member this.WidgetName = "Widget1"
module WidgetsModule =
let widgetName = "Widget2"
Om hela innehållet i filen finns i en modul kan du även deklarera namnområden implicit med hjälp av nyckelordet module
och ange det nya namnområdesnamnet i det fullständigt kvalificerade modulnamnet. I följande exempel visas en kodfil som deklarerar ett namnområde Widgets
och en modul WidgetsModule
, som innehåller en funktion.
module Widgets.WidgetModule
let widgetFunction x y =
printfn "%A %A" x y
Följande kod motsvarar föregående kod, men modulen är en lokal moduldeklaration. I så fall måste namnområdet visas på sin egen rad.
namespace Widgets
module WidgetModule =
let widgetFunction x y =
printfn "%A %A" x y
Om mer än en modul krävs i samma fil i en eller flera namnområden måste du använda lokala moduldeklarationer. När du använder lokala moduldeklarationer kan du inte använda det kvalificerade namnområdet i moduldeklarationerna. Följande kod visar en fil som har en namnområdesdeklaration och två lokala moduldeklarationer. I det här fallet finns modulerna direkt i namnområdet. det finns ingen implicit skapad modul som har samma namn som filen. All annan kod i filen, till exempel en do
bindning, finns i namnområdet men inte i de inre modulerna, så du måste kvalificera modulmedlemmen widgetFunction
med hjälp av modulnamnet.
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
Utdata från det här exemplet är följande.
Module1 10 20
Module2 5 6
Mer information finns i Moduler.
Kapslade namnområden
När du skapar ett kapslat namnområde måste du kvalificera det fullt ut. Annars skapar du ett nytt toppnivånamnområde. Indrag ignoreras i namnområdesdeklarationer.
I följande exempel visas hur du deklarerar ett kapslat namnområde.
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"
Namnområden i filer och sammansättningar
Namnområden kan sträcka sig över flera filer i ett enda projekt eller en kompilering. Termen namnområdesfragment beskriver den del av ett namnområde som ingår i en fil. Namnområden kan också sträcka sig över flera sammansättningar. Namnområdet innehåller till exempel System
hela .NET Framework, som sträcker sig över många sammansättningar och innehåller många kapslade namnområden.
Globalt namnområde
Du använder det fördefinierade namnområdet global
för att placera namn i .NET-namnområdet på den översta nivån.
namespace global
type SomeType() =
member this.SomeMember = 0
Du kan också använda global för att referera till .NET-namnområdet på den översta nivån, till exempel för att lösa namnkonflikter med andra namnområden.
global.System.Console.WriteLine("Hello World!")
Rekursiva namnområden
Namnrymder kan också deklareras som rekursiva så att all innesluten kod kan vara ömsesidigt rekursiv. Detta görs via namespace rec
. Användning av namespace rec
kan lindra vissa smärtor i att inte kunna skriva ömsesidigt referenskod mellan typer och moduler. Följande är ett exempel på detta:
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 (banana: Banana) =
let flip (banana: Banana) =
match banana.Orientation with
| Up ->
banana.Orientation <- Down
banana
| Down -> banana
// Update the peel state for all sides of the banana.
let peelSides (banana: Banana) =
banana.Sides
|> List.map (function
| Unpeeled -> Peeled
| Peeled -> Peeled)
// Apply the flipping and peeling logic based on the orientation.
match banana.Orientation with
| Up -> banana |> flip |> peelSides
| Down -> banana |> peelSides
Observera att både undantaget DontSqueezeTheBananaException
och klassen Banana
refererar till varandra. Dessutom refererar modulen BananaHelpers
och klassen Banana
till varandra. Detta skulle inte vara möjligt att uttrycka i F# om du tog bort nyckelordet rec
MutualReferences
från namnområdet.
Den här funktionen är också tillgänglig för moduler på den översta nivån.