Moduler
I samband med F#är en modul en gruppering av F#-kod, till exempel värden, typer och funktionsvärden, i ett F#-program. Genom att gruppera kod i moduler kan du hålla ihop relaterad kod och undvika namnkonflikter i programmet.
Syntax
// Top-level module declaration.
module [accessibility-modifier] [qualified-namespace.]module-name
declarations
// Local module declaration.
module [accessibility-modifier] module-name =
declarations
Kommentarer
En F#-modul är en gruppering av F#-kodkonstruktioner som typer, värden, funktionsvärden och kod i do
bindningar. Den implementeras som en CLR-klass (Common Language Runtime) som bara har statiska medlemmar. Det finns två typer av moduldeklarationer, beroende på om hela filen ingår i modulen: en moduldeklaration på den översta nivån och en lokal moduldeklaration. En moduldeklaration på den översta nivån innehåller hela filen i modulen. En moduldeklaration på den översta nivån kan bara visas som den första deklarationen i en fil.
I syntaxen för moduldeklarationen på den översta nivån är det valfria kvalificerade namnområdet sekvensen med kapslade namnområdesnamn som innehåller modulen. Det kvalificerade namnområdet behöver inte deklareras tidigare.
Du behöver inte dra in deklarationer i en modul på den översta nivån. Du måste dra in alla deklarationer i lokala moduler. I en lokal moduldeklaration ingår endast de deklarationer som är indragna under moduldeklarationen i modulen.
Om en kodfil inte börjar med en moduldeklaration på den översta nivån eller en namnområdesdeklaration, blir hela innehållet i filen, inklusive eventuella lokala moduler, en del av en implicit skapad modul på den översta nivån som har samma namn som filen, utan tillägget, med den första bokstaven konverterad till versaler. Tänk till exempel på följande fil.
// In the file program.fs.
let x = 40
Den här filen kompileras som om den hade skrivits på det här sättet:
module Program
let x = 40
Om du har flera moduler i en fil måste du använda en lokal moduldeklaration för varje modul. Om ett omslutande namnområde deklareras ingår dessa moduler i det omslutande namnområdet. Om ett omslutande namnområde inte deklareras blir modulerna en del av den implicit skapade modulen på den översta nivån. I följande kodexempel visas en kodfil som innehåller flera moduler. Kompilatorn skapar implicit en modul på den översta nivån med namnet Multiplemodules
och MyModule1
MyModule2
är kapslade i modulen på den översta nivån.
// 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)
Om du har flera filer i ett projekt eller i en enda kompilering, eller om du skapar ett bibliotek, måste du inkludera en namnområdesdeklaration eller moduldeklaration överst i filen. F#-kompilatorn bestämmer bara ett modulnamn implicit när det bara finns en fil i ett projekt eller en kompileringskommandorad och du skapar ett program.
Hjälpmedelsmodifierarenkan vara något av följande: public
, private
, internal
. Mer information finns i Åtkomstkontroll. Standardvärdet är offentligt.
Referera till kod i moduler
När du refererar till funktioner, typer och värden från en annan modul måste du antingen använda ett kvalificerat namn eller öppna modulen. Om du använder ett kvalificerat namn måste du ange namnrymderna, modulen och identifieraren för det programelement som du vill använda. Du separerar varje del av den kvalificerade sökvägen med en punkt (.), enligt följande.
Namespace1.Namespace2.ModuleName.Identifier
Du kan öppna modulen eller en eller flera av namnrymderna för att förenkla koden. Mer information om hur du öppnar namnrymder och moduler finns i Importera deklarationer: Nyckelordetopen
.
I följande kodexempel visas en modul på den översta nivån som innehåller all kod fram till slutet av filen.
module Arithmetic
let add x y =
x + y
let sub x y =
x - y
Om du vill använda den här koden från en annan fil i samma projekt använder du antingen kvalificerade namn eller så öppnar du modulen innan du använder funktionerna, som du ser i följande exempel.
// Fully qualify the function name.
let result1 = Arithmetic.add 5 9
// Open the module.
open Arithmetic
let result2 = add 5 9
Kapslade moduler
Moduler kan kapslas. Inre moduler måste vara indragna så långt som yttre moduldeklarationer för att indikera att de är inre moduler, inte nya moduler. Jämför till exempel följande två exempel. Modulen Z
är en inre modul i följande kod.
module Y =
let x = 1
module Z =
let z = 5
Men modulen Z
är ett syskon till modulen Y
i följande kod.
module Y =
let x = 1
module Z =
let z = 5
Modulen Z
är också en syskonmodul i följande kod eftersom den inte är indragen så långt som andra deklarationer i modulen Y
.
module Y =
let x = 1
module Z =
let z = 5
Slutligen, om den yttre modulen inte har några deklarationer och följs omedelbart av en annan moduldeklaration, antas den nya moduldeklarationen vara en inre modul, men kompilatorn varnar dig om den andra moduldefinitionen inte är indragen längre än den första.
// This code produces a warning, but treats Z as a inner module.
module Y =
module Z =
let z = 5
Om du vill eliminera varningen drar du in den inre modulen.
module Y =
module Z =
let z = 5
Om du vill att all kod i en fil ska finnas i en enda yttre modul och du vill ha inre moduler, kräver den yttre modulen inte likhetstecknet, och deklarationerna, inklusive eventuella inre moduldeklarationer, som kommer att gå i den yttre modulen behöver inte dras in. Deklarationer i de inre moduldeklarationerna måste dras in. Följande kod visar det här fallet.
// 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
Rekursiva moduler
F# 4.1 introducerar begreppet moduler som gör att all innesluten kod kan vara ömsesidigt rekursiv. Detta görs via module rec
. Användning av module rec
kan lindra vissa smärtor i att inte kunna skriva ömsesidigt referenskod mellan typer och moduler. Följande är ett exempel på detta:
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
Observera att både undantaget DontSqueezeTheBananaException
och klassen Banana
refererar till varandra. Dessutom refererar modulen BananaHelpers
och klassen Banana
till varandra. Detta skulle inte vara möjligt att uttrycka i F# om du tog bort nyckelordet rec
från modulen RecursiveModule
.
Den här funktionen är också möjlig i Namnområden med F# 4.1.