Поделиться через


Модули

В контексте F#модуль представляет собой группирование кода F#, например значений, типов и значений функций в программе F#. Код группирования в модулях объединяет связанный код и помогает избежать конфликтов имен в программе.

Синтаксис

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

Замечания

Модуль F# — это группирование конструкций кода F#, таких как типы, значения, значения функций и код в do привязках. Он реализуется как класс среды CLR, имеющий только статические члены. Существует два типа объявлений модуля в зависимости от того, включен ли весь файл в модуль: объявление модуля верхнего уровня и локальное объявление модуля. Объявление модуля верхнего уровня включает весь файл в модуле. Объявление модуля верхнего уровня может отображаться только как первое объявление в файле.

В синтаксисе объявления модуля верхнего уровня необязательный пробел имен — это последовательность вложенных имен пространств имен, содержащих модуль. Полное пространство имен не должно быть объявлено ранее.

Не требуется отступы в модуле верхнего уровня. Необходимо отступить все объявления в локальных модулях. В объявлении локального модуля только объявления, отступы которых находятся в этом объявлении модуля, являются частью модуля.

Если файл кода не начинается с объявления модуля верхнего уровня или объявления пространства имен, все содержимое файла, включая локальные модули, становится частью неявно созданного модуля верхнего уровня с тем же именем, что и файл без расширения, с первой буквой, преобразованной в верхний регистр. Например, рассмотрим следующий файл.

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

Этот файл будет скомпилирован так, как если бы он был написан таким образом:

module Program
let x = 40

При наличии нескольких модулей в файле необходимо использовать локальное объявление модуля для каждого модуля. Если объявлено заключенное пространство имен, эти модули являются частью включающего пространства имен. Если включающее пространство имен не объявлено, модули становятся частью неявно созданного модуля верхнего уровня. В следующем примере кода показан файл кода, содержащий несколько модулей. Компилятор неявно создает модуль верхнего уровня с именем Multiplemodulesи MyModule1MyModule2 вложен в этот модуль верхнего уровня.

// 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)

Если у вас несколько файлов в проекте или в одной компиляции или при создании библиотеки, необходимо включить объявление пространства имен или объявление модуля в верхней части файла. Компилятор F# определяет только имя модуля неявно, если в проекте или командной строке компиляции существует только один файл, и вы создаете приложение.

Модификатор специальных возможностей может быть одним из следующихpublic: , private. internal Дополнительные сведения см. в разделе Access Control. Значение по умолчанию: public.

Ссылка на код в модулях

При ссылке на функции, типы и значения из другого модуля необходимо использовать полное имя или открыть модуль. Если вы используете полное имя, необходимо указать пространства имен, модуль и идентификатор нужного элемента программы. Вы отделяете каждую часть квалифицированного пути точкой (.), как показано ниже.

Namespace1.Namespace2.ModuleName.Identifier

Чтобы упростить код, можно открыть модуль или несколько пространств имен. Дополнительные сведения об открытии пространств имен и модулей см. в разделе "Объявления импорта: ключевое open слово".

В следующем примере кода показан модуль верхнего уровня, содержащий весь код до конца файла.

module Arithmetic

let add x y =
    x + y

let sub x y =
    x - y

Чтобы использовать этот код из другого файла в том же проекте, следует использовать полные имена или открыть модуль перед использованием функций, как показано в следующих примерах.

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

Вложенные модули

Модули можно вложить. Внутренние модули должны быть отступлены до объявления внешнего модуля, чтобы указать, что они являются внутренними модулями, а не новыми модулями. Например, сравните следующие два примера. Модуль является внутренним модулем Z в следующем коде.

module Y =
    let x = 1

    module Z =
        let z = 5

Но модуль является одноуровневой для модуля ZY в следующем коде.

module Y =
    let x = 1

module Z =
    let z = 5

Модуль Z также является одноуровневой модулем в следующем коде, так как он не отступен до других объявлений в модуле Y.

module Y =
        let x = 1

    module Z =
        let z = 5

Наконец, если внешний модуль не имеет объявлений и немедленно следует другому объявлению модуля, новое объявление модуля считается внутренним модулем, но компилятор будет предупреждать вас, если второе определение модуля не отступило дальше, чем первое.

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

Чтобы устранить предупреждение, отступите внутренний модуль.

module Y =
    module Z =
        let z = 5

Если вы хотите, чтобы весь код в файле был в одном внешнем модуле и требуется внутренний модуль, внешний модуль не требует знака равенства и объявлений, включая любые объявления внутреннего модуля, которые будут использоваться во внешнем модуле, не должны быть отступлены. Объявления внутри внутренних объявлений модуля должны быть отступными. В следующем примере кода показано это дело.

// 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

Рекурсивные модули

F# 4.1 представляет понятие модулей, которые позволяют всем содержащимся кодам быть взаимокурсивным. Это делается с помощью module rec. module rec Использование может облегчить некоторые проблемы в том, что не удается писать взаимонаправленный код между типами и модулями. Ниже приведен пример:

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

Обратите внимание, что исключение DontSqueezeTheBananaException и класс Banana ссылаются друг на друга. Кроме того, модуль BananaHelpers и класс Banana также ссылаются друг на друга. Это не может быть возможным, если вы удалили rec ключевое слово из RecursiveModule модуля.

Эта возможность также возможна в пространствах имен с F# 4.1.

См. также