命名空間 (F#)
命名空間可讓您將名稱附加至 F# 程式元素的群組,以將程式碼依相關功能分類。 命名空間通常是 F# 檔案中的最上層元素。
語法
namespace [rec] [parent-namespaces.]identifier
備註
如果您想要將程式碼放在命名空間中,檔案中的第一個宣告必須宣告命名空間。 整個檔案的內容隨後將成為命名空間的一部分,前提是檔案中沒有其他命名空間宣告存在。 若是如此,則下一個命名空間宣告之前的所有程式碼,都會被視為在第一個命名空間內。
命名空間無法直接包含值和函式。 值和函式必須包含在模組中,而模組再包含於命名空間中。 命名空間可包含型別和模組。
XML 文件註解可宣告於命名空間之上,但會被忽略。 編譯器指示詞也可宣告於命名空間之上。
命名空間可以使用 namespace 關鍵字明確宣告,或在宣告模組時隱含宣告。 若要明確宣告命名空間,請使用 namespace 關鍵字,後面再加上命名空間名稱。 下列範例顯示的程式碼檔案會宣告含有型別和模組的命名空間 Widgets
。
namespace Widgets
type MyWidget1 =
member this.WidgetName = "Widget1"
module WidgetsModule =
let widgetName = "Widget2"
如果檔案的完整內容位於一個模組中,您也可以使用 module
關鍵字,並在完整模組名稱中提供新的命名空間名稱,以隱含地宣告命名空間。 下列範例顯示的程式碼檔案會宣告命名空間 Widgets
和模組 WidgetsModule
,其中包含一個函式。
module Widgets.WidgetModule
let widgetFunction x y =
printfn "%A %A" x y
下列程式碼相當於前述程式碼,但其模組是本機模組宣告。 在此情況下,命名空間必須單獨出現在一行上。
namespace Widgets
module WidgetModule =
let widgetFunction x y =
printfn "%A %A" x y
如果一或多個命名空間中的相同檔案中需要多個模組,您就必須使用本機模組宣告。 使用本機模組宣告時,您無法在模組宣告中使用限定的命名空間。 下列程式碼顯示具有一個命名空間宣告和兩個本機模組宣告的檔案。 在此案例中,模組直接包含在命名空間中;沒有隱含建立的模組與該檔案同名。 檔案中的任何其他程式碼 (例如 do
繫結) 都位於命名空間中,但不在內部模組中,因此您必須使用模組名稱來限定模組成員 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
如需詳細資訊,請參閱模組。
巢狀命名空間
在建立巢狀命名空間時,必須完整加以限定。 否則,您會建立新的最上層命名空間。 命名空間宣告會忽略縮排。
下列範例說明如何宣告巢狀命名空間。
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"
檔案和組件中的命名空間
命名空間可以跨越單一專案或編譯中的多個檔案。 命名空間片段一詞描述包含在一個檔案中的命名空間部分。 命名空間也可以跨越多個組件。 例如,System
命名空間包含整個 .NET Framework,跨越了許多組件,並且包含許多巢狀命名空間。
全域命名空間
您可以使用預先定義的命名空間 global
,將名稱放在 .NET 最上層命名空間中。
namespace global
type SomeType() =
member this.SomeMember = 0
您也可以使用全域來參考最上層 .NET 命名空間,例如,用來解決與其他命名空間的名稱衝突。
global.System.Console.WriteLine("Hello World!")
遞迴命名空間
命名空間也可以宣告為遞迴,以允許所有內含的程式碼相互遞迴。 這可透過 namespace rec
來完成。 使用 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
也會彼此參考。 如果您已從 MutualReferences
命名空間中移除 rec
關鍵字,就無法在 F# 中表達。
此功能也適用於最上層模組。