Moduly

V kontextu jazyka F# je modul seskupením kódu jazyka F#, jako jsou hodnoty, typy a hodnoty funkcí v programu jazyka F#. Seskupování kódu v modulech pomáhá udržet související kód pohromadě a pomáhá vyhnout se konfliktům názvů ve vašem programu.

Syntaxe

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

Poznámky

Modul F# je seskupení konstruktorů kódu jazyka F#, jako jsou typy, hodnoty, hodnoty funkcí a kód v do vazbách. Implementuje se jako třída CLR (Common Language Runtime), která má pouze statické členy. Existují dva typy deklarací modulů v závislosti na tom, jestli je celý soubor součástí modulu: deklarace modulu nejvyšší úrovně a deklarace místního modulu. Deklarace modulu nejvyšší úrovně zahrnuje celý soubor v modulu. Deklarace modulu nejvyšší úrovně se může zobrazit pouze jako první deklarace v souboru.

V syntaxi deklarace modulu nejvyšší úrovně je volitelný kvalifikovaný obor názvů posloupnost vnořených názvů oborů názvů, která obsahuje modul. Kvalifikovaný obor názvů nemusí být dříve deklarován.

V modulu nejvyšší úrovně nemusíte odsazení deklarací. Musíte odsadit všechny deklarace v místních modulech. V deklaraci místního modulu jsou součástí modulu pouze deklarace, které jsou odsazené v rámci deklarace modulu.

Pokud soubor kódu nezačíná deklarací modulu nejvyšší úrovně nebo deklarací oboru názvů, celý obsah souboru, včetně místních modulů, se stane součástí implicitně vytvořeného modulu nejvyšší úrovně, který má stejný název jako soubor bez přípony, s prvním písmenem převedeným na velká písmena. Představte si například následující soubor.

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

Tento soubor by se zkompiloval tak, jako by byl napsán tímto způsobem:

module Program
let x = 40

Pokud máte v souboru více modulů, musíte pro každý modul použít deklaraci místního modulu. Pokud je deklarován uzavřený obor názvů, jsou tyto moduly součástí nadřazeného oboru názvů. Pokud není deklarován uzavřený obor názvů, moduly se stanou součástí implicitně vytvořeného modulu nejvyšší úrovně. Následující příklad kódu ukazuje soubor kódu, který obsahuje více modulů. Kompilátor implicitně vytvoří modul nejvyšší úrovně s názvem Multiplemodulesa MyModule1MyModule2 je vnořený do daného modulu nejvyšší úrovně.

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

Pokud máte v projektu nebo v jedné kompilaci více souborů nebo pokud vytváříte knihovnu, musíte do horní části souboru zahrnout deklaraci oboru názvů nebo deklaraci modulu. Kompilátor jazyka F# určuje název modulu implicitně pouze v případě, že v projektu nebo kompilačním příkazovém řádku existuje pouze jeden soubor a vytváříte aplikaci.

Modifikátor přístupnosti může být jeden z následujících: public, private, internal. Další informace najdete v článku Access Control. Výchozí hodnota je veřejná.

Odkazování na kód v modulech

Pokud odkazujete na funkce, typy a hodnoty z jiného modulu, musíte buď použít kvalifikovaný název, nebo otevřít modul. Pokud použijete kvalifikovaný název, musíte zadat obory názvů, modul a identifikátor požadovaného prvku programu. Jednotlivé části kvalifikované cesty oddělíte tečkou (.) následujícím způsobem.

Namespace1.Namespace2.ModuleName.Identifier

Pokud chcete kód zjednodušit, můžete otevřít modul nebo jeden nebo více oborů názvů. Další informace o otevírání oborů názvů a modulů naleznete v tématu Import Deklarace: Klíčové open slovo.

Následující příklad kódu ukazuje modul nejvyšší úrovně, který obsahuje veškerý kód až do konce souboru.

module Arithmetic

let add x y =
    x + y

let sub x y =
    x - y

Pokud chcete tento kód použít z jiného souboru ve stejném projektu, použijte buď kvalifikované názvy, nebo modul otevřete před použitím funkcí, jak je znázorněno v následujících příkladech.

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

Vnořené moduly

Moduly je možné vnořit. Vnitřní moduly musí být odsazené, pokud jde o deklarace vnějšího modulu, aby bylo možné indikovat, že se jedná o vnitřní moduly, nikoli o nové moduly. Porovnejte například následující dva příklady. Modul Z je vnitřní modul v následujícím kódu.

module Y =
    let x = 1

    module Z =
        let z = 5

Z Modul je ale stejný jako modul Y v následujícím kódu.

module Y =
    let x = 1

module Z =
    let z = 5

Modul Z je také modul na stejné straně v následujícím kódu, protože není odsazený, pokud jde o další deklarace v modulu Y.

module Y =
        let x = 1

    module Z =
        let z = 5

A konečně, pokud vnější modul nemá žádné deklarace a následuje bezprostředně za jinou deklarací modulu, předpokládá se, že nová deklarace modulu je vnitřní modul, ale kompilátor vás upozorní, pokud druhá definice modulu není odsazená dál než první.

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

Pokud chcete upozornění odstranit, odsadíte vnitřní modul.

module Y =
    module Z =
        let z = 5

Pokud chcete, aby byl veškerý kód v souboru v jednom vnějším modulu a chcete vnitřní moduly, vnější modul nevyžaduje znaménko rovná se a deklarace, včetně deklarací vnitřních modulů, které se přesunou do vnějšího modulu, nemusí být odsazené. Deklarace uvnitř deklarací vnitřního modulu musí být odsazené. Následující kód ukazuje tento případ.

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

Rekurzivní moduly

F# 4.1 zavádí pojem modulů, které umožňují vzájemně rekurzivní veškerý obsažený kód. To se provádí prostřednictvím module rec. module rec Použití může zmírnit některé bolesti v tom, že nedokáže zapisovat vzájemně odkazující kód mezi typy a moduly. Následuje příklad:

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

Všimněte si, že výjimka DontSqueezeTheBananaException a třída Banana se vzájemně odkazují. Modul BananaHelpers a třída Banana se navíc vzájemně odkazují. Pokud jste z modulu odebrali rec klíčové slovo, není možné ho RecursiveModule v jazyce F# vyjádřit.

Tato funkce je také možná v oborech názvů s jazykem F# 4.1.

Viz také