命名空間使你能夠?qū)⒁粋€名稱附加到一組 F # 程序元素,從而將代碼組織到相關(guān)功能的區(qū)域中。 命名空間通常是 F # 文件中的頂級元素。
namespace [rec] [parent-namespaces.]identifier
注意:
- 如果要將代碼放入命名空間中,則文件中的第一個聲明必須聲明命名空間。 如果文件中不存在其他命名空間聲明,則整個文件的內(nèi)容將成為命名空間的一部分。 如果是這種情況,則所有代碼直到下一個命名空間聲明都被視為位于第一個命名空間內(nèi)。
- 命名空間不能直接包含值和函數(shù)。 相反,值和函數(shù)必須包含在模塊中,且模塊包含在命名空間中。 命名空間可以包含類型和模塊。
- XML 文檔注釋可以在命名空間之上聲明,但會被忽略。 還可以在命名空間之上聲明編譯器指令。
可以使用 namespace 關(guān)鍵字顯式聲明命名空間,或在聲明模塊時隱式聲明命名空間。 若要顯式聲明命名空間,請使用 namespace 關(guān)鍵字,后跟命名空間名稱。 下面的示例演示一個代碼文件,該代碼文件Widgets聲明具有類型的命名空間和包含在該命名空間中的模塊。
namespace Widgets
type MyWidget1 =
member this.WidgetName = "Widget1"
module WidgetsModule =
let widgetName = "Widget2"
如果該文件的所有內(nèi)容都在一個模塊中,則還可以使用module
關(guān)鍵字隱式聲明命名空間,并在完全限定的模塊名稱中提供新的命名空間名稱。 下面的示例演示一個聲明命名空間Widgets
的代碼文件和一個包含WidgetsModule
函數(shù)的模塊。
module Widgets.WidgetModule
let widgetFunction x y =
printfn "%A %A" x y
下面的代碼等效于前面的代碼,但模塊為本地模塊聲明。 在這種情況下,命名空間必須出現(xiàn)在其自己的行上。
namespace Widgets
module WidgetModule =
let widgetFunction x y =
printfn "%A %A" x y
如果一個或多個命名空間中的同一文件中需要多個模塊,則必須使用本地模塊聲明。 使用本地模塊聲明時,不能在模塊聲明中使用限定的命名空間。 下面的代碼演示一個具有命名空間聲明和兩個本地模塊聲明的文件。 在這種情況下,模塊直接包含在命名空間中;沒有隱式創(chuàng)建的與該文件同名的模塊。 文件中的任何其他代碼(如do
綁定)都位于命名空間中,但不在內(nèi)部模塊中,因此需要使用模塊名稱來限定模塊widgetFunction
成員。
namespace Widgets
module WidgetModule1 =
let widgetFunction x y =
printfn "Module1 %A %A" x y
module WidgetModule2 =
let widgetFunction x y =
printfn "Module2 %A %A" x y
module useWidgets =
do
WidgetModule1.widgetFunction 10 20
WidgetModule2.widgetFunction 5 6
此示例的輸出如下所示。
Module1 10 20
Module2 5 6
創(chuàng)建嵌套命名空間時,必須完全限定該命名空間。 否則,將創(chuàng)建一個新的頂級命名空間。 命名空間聲明中將忽略縮進。
下面的示例演示如何聲明嵌套命名空間。
namespace Outer
// Full name: Outer.MyClass
type MyClass() =
member this.X(x) = x + 1
// Fully qualify any nested namespaces.
namespace Outer.Inner
// Full name: Outer.Inner.MyClass
type MyClass() =
member this.Prop1 = "X"
命名空間可跨單個項目或編譯中的多個文件。 術(shù)語 "命名空間片段" 描述包含在一個文件中的命名空間的一部分。 命名空間也可以跨多個程序集。 例如, System命名空間包含整個 .NET Framework,這跨多個程序集,并且包含許多嵌套命名空間。
使用預(yù)定義的命名 global 空間將名稱放在 .net 頂級命名空間中。
namespace global
type SomeType() =
member this.SomeMember = 0
你還可以使用 global 引用頂層 .NET 命名空間,例如,解析與其他命名空間的名稱沖突。
global.System.Console.WriteLine("Hello World!")
還可以將命名空間聲明為 recursive,以允許所有包含的代碼相互遞歸。 這是通過 namespace rec 實現(xiàn)的。 使用 namespace rec 可以減少無法在類型和模塊之間編寫相互引用代碼的一些難題。 下面是一個示例:
namespace rec MutualReferences
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 MutualReferences命名空間中刪除關(guān)鍵字,則無法在 F # 中表示。
更多建議: