Compartilhar via


Módulos

No contexto de F#, um módulo é um agrupamento de código F#, como valores, tipos e valores de função, em um programa F#. Agrupar código em módulos ajuda a manter o código relacionado unido e ajuda a evitar conflitos de nome em seu programa.

Sintaxe

// Top-level module declaration.
module [accessibility-modifier] [qualified-namespace.]module-name
declarations
// Local module declaration.
module [accessibility-modifier] module-name =
    declarations

Observações

Um módulo F# é um agrupamento de construções de código F#, como tipos, valores, valores de função e código em do associações. Ela é implementada como uma classe CLR (Common Language Runtime) que tem apenas membros estáticos. Há dois tipos de declarações de módulo, dependendo se o arquivo inteiro está incluído no módulo: uma declaração de módulo de nível superior e uma declaração de módulo local. Uma declaração de módulo de nível superior inclui todo o arquivo no módulo. Uma declaração de módulo de nível superior só pode aparecer como a primeira declaração em um arquivo.

Na sintaxe da declaração do módulo de nível superior, o namespace qualificado opcional é a sequência de nomes de namespace aninhados que contém o módulo. O namespace qualificado não precisa ser declarado anteriormente.

Você não precisa recuar declarações em um módulo de nível superior. Você precisa recuar todas as declarações em módulos locais. Em uma declaração de módulo local, somente as declarações que são recuadas sob essa declaração de módulo fazem parte do módulo.

Se um arquivo de código não começar com uma declaração de módulo de nível superior ou uma declaração de namespace, todo o conteúdo do arquivo, incluindo quaisquer módulos locais, se tornará parte de um módulo de nível superior criado implicitamente que tem o mesmo nome do arquivo, sem a extensão, com a primeira letra convertida em maiúscula. Por exemplo, considere o arquivo a seguir.

// In the file program.fs.
let x = 40

Esse arquivo seria compilado como se tivesse sido escrito dessa maneira:

module Program
let x = 40

Se você tiver vários módulos em um arquivo, deverá usar uma declaração de módulo local para cada módulo. Se um namespace delimitado for declarado, esses módulos serão parte do namespace delimitado. Se um namespace delimitador não for declarado, os módulos se tornarão parte do módulo de nível superior criado implicitamente. O exemplo de código a seguir mostra um arquivo de código que contém vários módulos. O compilador cria implicitamente um módulo de nível superior chamado Multiplemodulese MyModule1MyModule2 está aninhado nesse módulo de nível superior.

// In the file multiplemodules.fs.
// MyModule1
module MyModule1 =
    // Indent all program elements within modules that are declared with an equal sign.
    let module1Value = 100

    let module1Function x =
        x + 10

// MyModule2
module MyModule2 =

    let module2Value = 121

    // Use a qualified name to access the function.
    // from MyModule1.
    let module2Function x =
        x * (MyModule1.module1Function module2Value)

Se você tiver vários arquivos em um projeto ou em uma única compilação ou se estiver criando uma biblioteca, deverá incluir uma declaração de namespace ou declaração de módulo na parte superior do arquivo. O compilador F# determina apenas um nome de módulo implicitamente quando há apenas um arquivo em um projeto ou linha de comando de compilação e você está criando um aplicativo.

O modificador de acessibilidade pode ser um dos seguintes: public, , private. internal Para obter mais informações, consulte Controle de Acesso. O padrão é público.

Referenciando código em módulos

Ao fazer referência a funções, tipos e valores de outro módulo, você deve usar um nome qualificado ou abrir o módulo. Se você usar um nome qualificado, deverá especificar os namespaces, o módulo e o identificador do elemento de programa desejado. Você separa cada parte do caminho qualificado com um ponto (.), da seguinte maneira.

Namespace1.Namespace2.ModuleName.Identifier

Você pode abrir o módulo ou um ou mais namespaces para simplificar o código. Para obter mais informações sobre como abrir namespaces e módulos, consulte Import Declarations: The open Keyword.

O exemplo de código a seguir mostra um módulo de nível superior que contém todo o código até o final do arquivo.

module Arithmetic

let add x y =
    x + y

let sub x y =
    x - y

Para usar esse código de outro arquivo no mesmo projeto, use nomes qualificados ou abra o módulo antes de usar as funções, conforme mostrado nos exemplos a seguir.

// Fully qualify the function name.
let result1 = Arithmetic.add 5 9
// Open the module.
open Arithmetic
let result2 = add 5 9

Módulos aninhados

Os módulos podem ser aninhados. Os módulos internos devem ser recuados quanto às declarações do módulo externo para indicar que são módulos internos, não novos módulos. Por exemplo, compare os dois exemplos a seguir. O módulo Z é um módulo interno no código a seguir.

module Y =
    let x = 1

    module Z =
        let z = 5

Mas o módulo Z é um irmão para módulo Y no código a seguir.

module Y =
    let x = 1

module Z =
    let z = 5

O módulo Z também é um módulo irmão no código a seguir, pois não é recuado quanto a outras declarações no módulo Y.

module Y =
        let x = 1

    module Z =
        let z = 5

Por fim, se o módulo externo não tiver declarações e for seguido imediatamente por outra declaração de módulo, a nova declaração do módulo será considerada um módulo interno, mas o compilador avisará se a definição do segundo módulo não for recuada mais do que a primeira.

// This code produces a warning, but treats Z as a inner module.
module Y =
module Z =
    let z = 5

Para eliminar o aviso, recuo do módulo interno.

module Y =
    module Z =
        let z = 5

Se você quiser que todo o código em um arquivo esteja em um único módulo externo e desejar módulos internos, o módulo externo não exigirá o sinal de igual e as declarações, incluindo quaisquer declarações de módulo interno, que entrarão no módulo externo não precisarão ser recuadas. As declarações dentro das declarações do módulo interno precisam ser recuadas. O código a seguir mostra esse caso.

// The top-level module declaration can be omitted if the file is named
// TopLevel.fs or topLevel.fs, and the file is the only file in an
// application.
module TopLevel

let topLevelX = 5

module Inner1 =
    let inner1X = 1
module Inner2 =
    let inner2X = 5

Módulos recursivos

O F# 4.1 apresenta a noção de módulos que permitem que todo o código contido seja mutuamente recursivo. Isso é feito por meio de module rec. O uso pode module rec aliviar algumas dores ao não conseguir escrever código mutuamente referencial entre tipos e módulos. Veja a seguir um exemplo disso:

module rec RecursiveModule =
    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 Orientation = orientation with get, set
        member val Sides: PeelState list = [ Unpeeled; Unpeeled; Unpeeled; Unpeeled ] with get, set

        member self.IsPeeled =
            self.Sides |> List.forall ((=) Peeled)

        member self.Peel() =
            BananaHelpers.peel self
            |> fun peeledSides -> self.Sides <- peeledSides

        member self.SqueezeJuiceOut() =
            raise (DontSqueezeTheBananaException self)

    module BananaHelpers =
        let peel (banana: 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)

            banana |> flip |> peelSides

Observe que a exceção DontSqueezeTheBananaException e a classe Banana se referem umas às outras. Além disso, o módulo BananaHelpers e a classe Banana também se referem um ao outro. Isso não seria possível expressar em F# se você removesse a rec palavra-chave do RecursiveModule módulo.

Essa funcionalidade também é possível em Namespaces com F# 4.1.

Consulte também