Módulos
No contexto do F#, um módulo é um agrupamento de código F#, como valores, tipos e valores de função, em um programa F#. Agrupar o código em módulos ajuda a manter o código relacionado junto 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. Ele é implementado como uma classe CLR (Common Language Runtime) que tem apenas membros estáticos. Existem dois tipos de declarações de módulo, dependendo se todo o arquivo 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 pode aparecer apenas como a primeira declaração em um arquivo.
Na sintaxe da declaração de 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 previamente.
Não é necessário recuar declarações em um módulo de nível superior. É necessário 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, torna-se 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úsculas. Por exemplo, considere o seguinte arquivo.
// In the file program.fs.
let x = 40
Este arquivo seria compilado como se fosse escrito desta 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 de inclusão for declarado, esses módulos farão parte do namespace de delimitação. Se um namespace de inclusão 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 Multiplemodules
, e MyModule1
MyModule2
são aninhados 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# só determina 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.
Código de referência 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 para o elemento de programa desejado. Separe cada parte do caminho qualificado com um ponto (.), da seguinte forma.
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 Importar declarações: a open
palavra-chave.
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 até as declarações de módulo externo para indicar que são módulos internos, não novos módulos. Por exemplo, compare os dois exemplos a seguir. Módulo Z
é um módulo interno no código a seguir.
module Y =
let x = 1
module Z =
let z = 5
Mas 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
Módulo Z
também é um módulo irmão no código a seguir, porque ele não é recuado tanto quanto outras declarações no módulo Y
.
module Y =
let x = 1
module Z =
let z = 5
Finalmente, 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 de módulo será assumida como 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, recue o 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 quiser módulos internos, o módulo externo não requer o sinal de igual e as declarações, incluindo quaisquer declarações de módulo interno, que irão no módulo externo não precisam 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
F# 4.1 introduz a noção de módulos que permitem que todo o código contido seja mutuamente recursivo. Isto é feito através do module rec
. O uso de pode aliviar algumas dores em não ser capaz de module rec
escrever código mutuamente referencial entre tipos e módulos. Segue-se 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 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
Observe que a exceção DontSqueezeTheBananaException
e a classe Banana
se referem uma à outra. 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
RecursiveModule
palavra-chave do módulo.
Esse recurso também é possível em namespaces com F# 4.1.