Spazi dei nomi (F#)
Uno spazio dei nomi consente di organizzare il codice in aree di funzionalità correlate, consentendo di associare un nome a un raggruppamento di elementi del programma F#. Gli spazi dei nomi sono in genere elementi di primo livello nei file F#.
Sintassi
namespace [rec] [parent-namespaces.]identifier
Osservazioni:
Se si desidera inserire il codice in uno spazio dei nomi, la prima dichiarazione nel file deve dichiarare lo spazio dei nomi . Il contenuto dell'intero file diventa quindi parte dello spazio dei nomi, purché non esistano altre dichiarazioni di spazi dei nomi nel file. In tal caso, tutto il codice viene eseguito fino a quando non viene considerata la dichiarazione dello spazio dei nomi successiva all'interno del primo spazio dei nomi.
Gli spazi dei nomi non possono contenere direttamente valori e funzioni. I valori e le funzioni devono invece essere inclusi nei moduli e i moduli sono inclusi negli spazi dei nomi. Gli spazi dei nomi possono contenere tipi e moduli.
I commenti della documentazione XML possono essere dichiarati sopra uno spazio dei nomi, ma vengono ignorati. Le direttive del compilatore possono anche essere dichiarate sopra uno spazio dei nomi.
Gli spazi dei nomi possono essere dichiarati in modo esplicito con la parola chiave dello spazio dei nomi o in modo implicito durante la dichiarazione di un modulo. Per dichiarare uno spazio dei nomi in modo esplicito, usare la parola chiave namespace seguita dal nome dello spazio dei nomi. Nell'esempio seguente viene illustrato un file di codice che dichiara uno spazio dei nomi Widgets
con un tipo e un modulo incluso in tale spazio dei nomi.
namespace Widgets
type MyWidget1 =
member this.WidgetName = "Widget1"
module WidgetsModule =
let widgetName = "Widget2"
Se l'intero contenuto del file si trova in un modulo, è anche possibile dichiarare gli spazi dei nomi in modo implicito usando la module
parola chiave e specificando il nuovo nome dello spazio dei nomi nel nome completo del modulo. L'esempio seguente mostra un file di codice che dichiara uno spazio dei nomi Widgets
e un modulo WidgetsModule
, che contiene una funzione.
module Widgets.WidgetModule
let widgetFunction x y =
printfn "%A %A" x y
Il codice seguente è equivalente al codice precedente, ma il modulo è una dichiarazione di modulo locale. In tal caso, lo spazio dei nomi deve essere visualizzato sulla propria riga.
namespace Widgets
module WidgetModule =
let widgetFunction x y =
printfn "%A %A" x y
Se più moduli sono necessari nello stesso file in uno o più spazi dei nomi, è necessario usare le dichiarazioni di modulo locale. Quando si usano dichiarazioni di modulo locali, non è possibile usare lo spazio dei nomi qualificato nelle dichiarazioni del modulo. Il codice seguente mostra un file con una dichiarazione dello spazio dei nomi e due dichiarazioni di modulo locale. In questo caso, i moduli sono contenuti direttamente nello spazio dei nomi; non esiste un modulo creato in modo implicito con lo stesso nome del file. Qualsiasi altro codice nel file, ad esempio un'associazione do
, si trova nello spazio dei nomi ma non nei moduli interni, quindi è necessario qualificare il membro widgetFunction
del modulo usando il nome del modulo.
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
L'output di questo esempio è il seguente.
Module1 10 20
Module2 5 6
Per altre informazioni, vedere Moduli.
Spazi dei nomi annidati
Quando si crea uno spazio dei nomi annidato, è necessario qualificarlo completamente. In caso contrario, si crea un nuovo spazio dei nomi di primo livello. Il rientro viene ignorato nelle dichiarazioni dello spazio dei nomi.
Nell'esempio seguente viene illustrato come dichiarare uno spazio dei nomi annidato.
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"
Spazi dei nomi in file e assembly
Gli spazi dei nomi possono estendersi a più file in un singolo progetto o compilazione. Il termine frammento dello spazio dei nomi descrive la parte di uno spazio dei nomi incluso in un unico file. Gli spazi dei nomi possono anche estendersi a più assembly. Ad esempio, lo System
spazio dei nomi include l'intero .NET Framework, che si estende su molti assembly e contiene molti spazi dei nomi annidati.
Spazio dei nomi globale
Usare lo spazio dei nomi predefinito per inserire i nomi nello spazio global
dei nomi di primo livello .NET.
namespace global
type SomeType() =
member this.SomeMember = 0
È anche possibile usare global per fare riferimento allo spazio dei nomi .NET di primo livello, ad esempio per risolvere i conflitti di nomi con altri spazi dei nomi.
global.System.Console.WriteLine("Hello World!")
Spazi dei nomi ricorsivi
Gli spazi dei nomi possono anche essere dichiarati come ricorsivi per consentire a tutto il codice contenuto di essere ricorsivo a vicenda. Questa operazione viene eseguita tramite namespace rec
. L'uso di namespace rec
può alleviare alcuni dolori in non essere in grado di scrivere codice referenziale reciproca tra tipi e moduli. Di seguito è riportato un esempio:
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
Si noti che l'eccezione DontSqueezeTheBananaException
e la classe Banana
si riferiscono l'una all'altra. Inoltre, il modulo BananaHelpers
e la classe Banana
si riferiscono l'uno all'altro. Non sarebbe possibile esprimere in F# se la rec
parola chiave è stata rimossa dallo spazio dei MutualReferences
nomi .
Questa funzionalità è disponibile anche per i moduli di primo livello.