Espaces de noms (F#)

Un espace de noms vous permet d’organiser le code en zones de fonctionnalités connexes. Pour cela, vous attachez un nom à un regroupement d’éléments de programme F#. Les espaces de noms sont généralement des éléments de niveau supérieur dans les fichiers F#.

Syntaxe

namespace [rec] [parent-namespaces.]identifier

Notes

Si vous souhaitez placer du code dans un espace de noms, la première déclaration du fichier doit déclarer l’espace de noms. Le contenu du fichier entier fait ensuite partie de l’espace de noms, à condition qu’aucune autre déclaration d’espace de noms n’existe dans le fichier. Si c’est le cas, tout le code jusqu’à la prochaine déclaration d’espace de noms est considéré comme faisant partie du premier espace de noms.

Les espaces de noms ne peuvent pas contenir directement des valeurs et des fonctions. Au lieu de cela, les valeurs et les fonctions doivent être incluses dans les modules, et les modules sont inclus dans les espaces de noms. Les espaces de noms peuvent contenir des types et des modules.

Les commentaires de documentation XML peuvent être déclarés au-dessus d’un espace de noms, mais ils sont ignorés. Les directives du compilateur peuvent également être déclarées au-dessus d’un espace de noms.

Les espaces de noms peuvent être déclarés explicitement avec le mot clé d’espace de noms, ou implicitement lors de la déclaration d’un module. Pour déclarer explicitement un espace de noms, utilisez le mot clé d’espace de noms suivi du nom de l’espace de noms. L’exemple suivant montre un fichier de code qui déclare un espace de noms Widgets avec un type et un module inclus dans cet espace de noms.

namespace Widgets

type MyWidget1 =
    member this.WidgetName = "Widget1"

module WidgetsModule =
    let widgetName = "Widget2"

Si l’intégralité du contenu du fichier se trouve dans un module, vous pouvez également déclarer implicitement des espaces de noms à l’aide du mot clé module et fournir le nouveau nom d’espace de noms dans le nom du module complet. L’exemple suivant montre un fichier de code qui déclare un espace de noms Widgets et un module WidgetsModule, qui contient une fonction.

module Widgets.WidgetModule

let widgetFunction x y =
   printfn "%A %A" x y

Le code suivant équivaut au code précédent, mais le module est une déclaration de module local. Dans ce cas, l’espace de noms doit apparaître sur sa propre ligne.

namespace Widgets

module WidgetModule =

    let widgetFunction x y =
        printfn "%A %A" x y

Si plusieurs modules sont requis dans le même fichier dans un ou plusieurs espaces de noms, vous devez utiliser des déclarations de module local. Lorsque vous utilisez des déclarations de module local, vous ne pouvez pas utiliser l’espace de noms qualifié dans les déclarations de module. Le code suivant montre un fichier qui a une déclaration d’espace de noms et deux déclarations de module local. Dans ce cas, les modules sont contenus directement dans l’espace de noms ; il n’existe aucun module créé implicitement portant le même nom que le fichier. Tout autre code du fichier, tel qu’une liaison do, se trouve dans l’espace de noms, mais pas dans les modules internes. Vous devez donc qualifier le membre widgetFunction du module à l’aide du nom du module.

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

La sortie de cet exemple est la suivante.

Module1 10 20
Module2 5 6

Pour plus d’informations, consultez Modules.

Espaces de noms imbriqués

Lorsque vous créez un espace de noms imbriqué, vous devez le qualifier entièrement. Sinon, vous créez un espace de noms de niveau supérieur. La mise en retrait est ignorée dans les déclarations d’espace de noms.

L’exemple suivant montre comment déclarer un espace de noms imbriqué.

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"

Espaces de noms dans les fichiers et les assemblys

Les espaces de noms peuvent s’étendre sur plusieurs fichiers dans un projet ou une compilation unique. Le fragment d’espace de noms de terme décrit la partie d’un espace de noms inclus dans un fichier. Les espaces de noms peuvent également s’étendre sur plusieurs assemblys. Par exemple, l’espace de noms System inclut l’ensemble du .NET Framework, qui s’étend sur de nombreux assemblys et contient de nombreux espaces de noms imbriqués.

Espace de noms global

Vous utilisez l’espace de noms global prédéfini pour placer des noms dans l’espace de noms de niveau supérieur .NET.

namespace global

type SomeType() =
    member this.SomeMember = 0

Vous pouvez également utiliser le global pour référencer l’espace de noms .NET de niveau supérieur, par exemple, pour résoudre les conflits de noms avec d’autres espaces de noms.

global.System.Console.WriteLine("Hello World!")

Espaces de noms récursifs

Les espaces de noms peuvent également être déclarés comme récursifs pour permettre à tout code contenu d’être mutuellement récursif. Cette opération est effectuée via namespace rec. L’utilisation de namespace rec peut soulager certaines douleurs dans l’impossibilité d’écrire du code référentiel mutuellement entre les types et les modules. Voici un exemple de ceci :

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

Notez que l’exception DontSqueezeTheBananaException et la classe Banana font référence les unes aux autres. En outre, le module BananaHelpers et la classe Banana font également référence les uns aux autres. Cela ne serait pas possible d’exprimer en F# si vous avez supprimé le mot clé rec de l’espace de noms MutualReferences.

Cette fonctionnalité est également disponible pour les modules de niveau supérieur.

Voir aussi