Espacios de nombres (F#)

Un espacio de nombres permite organizar el código en áreas de funcionalidad relacionada, lo que permite adjuntar un nombre a una agrupación de elementos de programa de F#. Normalmente, los espacios de nombres son elementos de nivel superior en archivos de F#.

Sintaxis

namespace [rec] [parent-namespaces.]identifier

Comentarios

Si quiere colocar código en un espacio de nombres, la primera declaración del archivo debe declarar el espacio de nombres. Después, el contenido del archivo al completo se convierte en parte del espacio de nombres, siempre y cuando no exista otra declaración de espacios de nombres en el archivo. Si ese es el caso, todo el código hasta la siguiente declaración de espacio de nombres se considera dentro del primer espacio de nombres.

Los espacios de nombres no pueden contener directamente valores y funciones. Los valores y las funciones deben incluirse en módulos, y estos se incluyen en espacios de nombres. Los espacios de nombres pueden contener tipos y módulos.

Los comentarios de documentación XML pueden declararse encima de un espacio de nombres, pero se omiten. Las directivas del compilador también se pueden declarar encima de un espacio de nombres.

Los espacios de nombres se pueden declarar explícitamente con la palabra clave namespace o implícitamente cuando se declara un módulo. Para declarar explícitamente un espacio de nombres, use la palabra clave namespace seguida del nombre del espacio de nombres. En el ejemplo siguiente se muestra un archivo de código en el que se declara un espacio de nombres Widgets con un tipo y un módulo incluidos en dicho espacio de nombres.

namespace Widgets

type MyWidget1 =
    member this.WidgetName = "Widget1"

module WidgetsModule =
    let widgetName = "Widget2"

Si todo el contenido del archivo se encuentra en un módulo, también se pueden declarar espacios de nombres implícitamente si se usa la palabra clave module y se proporciona el nuevo nombre de espacio de nombres en el nombre completo del módulo. En el ejemplo siguiente se muestra un archivo de código que declara un espacio de nombres Widgets y un módulo WidgetsModule, que contiene una función.

module Widgets.WidgetModule

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

El código siguiente es equivalente al código anterior, pero el módulo es una declaración de módulo local. En ese caso, el espacio de nombres debe aparecer en su propia línea.

namespace Widgets

module WidgetModule =

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

Si se requiere más de un módulo en el mismo archivo en uno o varios espacios de nombres, es necesario usar declaraciones de módulo local. Cuando se usan declaraciones de módulo local, no se puede usar el espacio de nombres completo en las declaraciones del módulo. En el código siguiente se muestra un archivo que tiene una declaración de espacio de nombres y dos declaraciones de módulo local. En este caso, los módulos están contenidos directamente en el espacio de nombres; no hay ningún módulo creado implícitamente que tenga el mismo nombre que el archivo. Cualquier otro código del archivo, como un enlace do, se encuentra en el espacio de nombres, pero no en los módulos internos, por lo que es necesario calificar el miembro de módulo widgetFunction mediante el nombre del módulo.

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

El resultado de este ejemplo es el que se muestra a continuación.

Module1 10 20
Module2 5 6

Para obtener más información, consulte Módulos.

Espacios de nombres anidados

Al crear un espacio de nombres anidado, debe calificarlo por completo. De lo contrario, se crea otro espacio de nombres de nivel superior. La sangría se omite en las declaraciones de espacio de nombres.

En el ejemplo siguiente se muestra cómo se declara un espacio de nombres anidado.

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"

Espacios de nombres en archivos y ensamblados

Los espacios de nombres pueden abarcar varios archivos de un proyecto o compilación. El término fragmento de espacio de nombres describe la parte de un espacio de nombres que está incluida en un archivo. Los espacios de nombres también pueden abarcar varios ensamblados. Por ejemplo, el espacio de nombres System incluye todo .NET Framework, que abarca muchos ensamblados y contiene muchos espacios de nombres anidados.

Espacio de nombres global

Use el espacio de nombres predefinido global para colocar nombres en el espacio de nombres de nivel superior de .NET.

namespace global

type SomeType() =
    member this.SomeMember = 0

También puede usar "global" para hacer referencia al espacio de nombres de .NET de nivel superior, por ejemplo, para resolver conflictos de nombres con otros espacios de nombres.

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

Espacios de nombres recursivos

Los espacios de nombres también se pueden declarar como recursivos para permitir que todo el código contenido sea mutuamente recursivo. Esto se hace mediante namespace rec. El uso de namespace rec puede reducir algunos problemas relacionados con la imposibilidad de escribir de código mutuamente referencial entre tipos y módulos. A continuación se muestra un ejemplo de esto:

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

Tenga en cuenta que tanto la excepción DontSqueezeTheBananaException como la clase Banana se hacen referencia entre sí. Además, el módulo BananaHelpers y la clase Banana también se hacen referencia entre sí. Esto no podría expresarse en F# si se quitara la palabra clave rec del espacio de nombres MutualReferences.

Esta característica también está disponible para los módulos de nivel superior.

Vea también