F#入門-第二章 F#基礎-第二十二節 模塊與命名空間

模塊
  
模塊是指將定義進行統一彙總並賦予名稱的功能。由於只將有關聯的定義進行統一彙總,所以可以提高代碼塊的獨立性。雖然F#中的模塊體系是從Ocaml中轉變而來的,但是與Ocaml不同的是:
    1.Functor等的一部分沒有被封裝進來
    2.模塊名可以是大寫字母,也可以是小寫字母

    模塊的定義可以用F#版或Ocaml版的兩種方式進行定義。

 F#版的模塊定義
    模塊定義:= begin [模塊元素]* end
    模塊元素:=
    | let表達式
    | type定義
    | 異常定義
    | 子模塊定義
    | 子模塊的省略名稱的定義
    | import聲明
    子模塊的省略名稱的定義:=
    module 省略名稱 = 模塊名

 

 Ocaml兼容版的模塊定義
    模塊定義:= struct [模塊元素]* end
    (其他部分與上相同)


    另外,加上#light語句的時候可以省略begin,end。
    接下來,讓我們看實際的模塊的例子。

模塊的創建
//最小的模塊。模塊名可以爲小寫字母
module a = begin end;;

//用let定義值
module b = begin let a = 2 end;;
//OCaml風格
module c = struct let a = 3 end;;
//訪問模塊時使用點符號
printfn "%d" (b.a);;
printfn "%d" (c.a);;


    上例中定義了a,b,c三個模塊。訪問模塊中定義好的元素時需要象上例中那樣加上點符號。

其他形式的模塊定義
//類型的定義。模塊名當然可以爲大寫字母
module D = begin type A = int end;;

//異常的定義
module E = begin exception EX end;;

//模塊的省略名稱的定義
module M = Microsoft.FSharp.Collections.Seq;;
//下面這句是錯誤的。System.Windows.Forms不是模塊而是命名空間(命名空間的介紹見後)
//module WF = System.Windows.Forms

//省略名稱的利用
M.map ((+)1) [1..10] |> print_any;;


    上例爲定義類型,異常,省略名稱的例子.

   
    接下來,可以定義複合模塊.

複合模塊
module Mix = begin
let a = 10
type T = int
exception E
end


    同時,模塊可以嵌套。

模塊嵌套
module A = begin
module B = begin
let b = 5
end
end;;
printfn "%d" (A.B.b);;


    對於模塊,雖然進行訪問時必須加上點符號,但是在比較麻煩的時候,可以對模塊進行open。

模塊的open
module A = begin
let a = 6
end;;
open A;;
printfn "%d" a;;


    在上例中定義了模塊A,由於對A模塊進行了open,所以訪問A模塊中的a元素時可以不加點符號。

    接下來,可以在模塊中直接使用open,這種情況下,模塊內的open不會影響到模塊之外。

模塊內的open
module A = begin
open List
let a = map ((+)1) [1..10]
end;;

A.a |> print_any;;
//error:The value or constructor 'map' is not defined
//map ((+)1) [1..10];;


    一般,不針對List模塊進行open,但是,在模塊A內部即使對List進行了open操作,也不會對模塊外產生任何影響,這種方法是可以使用的。

    更進一步來說,可以給模塊添加自動open的AutoOpen屬性(Microsoft.FSharp.Core.AutoOpenAttribute)。下例中將模塊進行嵌套並執行AutoOpen。

AutoOpen屬性
#light "off"

module A1 = begin
let a1 = 1
module B1 = begin let b1 = 11 end
end;;

module A2 = begin
let a2 = 2
[<AutoOpen>]
module B2 = begin let b2 = 22 end
end;;

[<AutoOpen>]
module A3 = begin
let a3 = 3
module B3 = begin let b3 = 33 end
end;;

[<AutoOpen>]
module A4 = begin
let a4 = 4
[<AutoOpen>]
module B4 = begin let b4 = 44 end
end;;
printfn "%d,%d" (A1.a1) (A1.B1.b1);;

printfn "%d,%d" (A2.a2) (A2.B2.b2);;
//printfn "%d,%d" (A2.a2) (A2.b2);; //此句不會顯示出所想要的結果

printfn "%d,%d" a3 (B3.b3);;

printfn "%d,%d" a4 b4;;


    可以確認加了AutoOpen屬性的模塊在被訪問時可以不加模塊名而直接訪問。

命名空間
    當程序的規模大到一定程度時,會產生函數或變量名互相沖突的問題。爲了解決這類問題,可以考慮使用命名空間。在.Net中定義了各種類庫,定義了不同語言的Microsoft.FSharp,Microsoft.CSharp,Microsoft.VisualBasic等很多命名空間。

    命名空間的定義形式基本如下:

 命名空間的定義
    封裝文件:= [命名空間的定義]*
    命名空間的定義:=
    | namespace 命名空間名 頂級模塊的定義
    | module 模塊名  模塊的元素
    | 模塊的元素


    舉例如下

命名空間的例子
namespace test
module A = begin let a = 1 end;;


    這個例子中定義了命名空間test與其中的模塊A。
    同樣也可以對命名空間進行open。

命名空間的open
//file1.fs
#light "off"

namespace test
module A = begin let a = 1 end;;
//main.fs
#light "off"

open test;;
printfn "%d" (A.a);;


    在這個例子中,在file1.fs文件中定義了命名空間test並在main.fs文件中對test命名空間進行open。另外,應該要注意的是,如果首先編譯了main.fs文件,則對file1.fs文件中的命名空間進行的open操作就不能正常執行了。關於這一點,請參考編譯器的使用方法一節中的程序裝載順序部分。

    使用命名空間時,與使用模塊不同的是:
    1.不能在定義命名空間的時候定義值(let等等)。
    2.不能在命名空間的定義前書寫針對編譯器進行的指示代碼。
    3.由於上述因素,不能對命名空間進行AutoOpen。
    4.命名空間不能被嵌套。
    5.命名空間沒有省略名稱。

    針對前面命名空間部分中的第一個例子,以下寫法會引起編譯錯誤。

錯誤示例
namespace A
let a = 1;;


    另外如前所述,命名空間不能被嵌套使用。雖然默認打開的命名空間(後文詳述)表面上看上去像是嵌套空間,但實際上是通過如下方式被打開的。

容易被誤解成嵌套空間的命名空間
namespace N
module A = begin let a = 1 end;;
namespace N.M
module B = begin let b = 2 end;;


    上例中的定義可以被象下例中所示地分階段打開。但是,1.9.6.2版本後不推薦這種打開方式。

分階段打開
open N;
open M;
print_any (B.b);;


    這是因爲,在F#中,原本是允許如下所示的打開方法的,但是現在推薦使用命名空間的完全名稱的打開方式。

命名空間的打開方式
open System
open Windows //現在編譯器會針對此處提出警告
open Forms
// open System.Windows.Forms //推薦的打開方法


    另外,在命名空間的定義部分的第2,3行中的函數分別被稱爲具名函數/匿名函數.因此,可以象下例那樣不加begin/end語句而直接定義模塊.

具名函數
module A
let a = 10;;


    另外,迄今爲止沒有定義模塊而直接書寫的代碼都在匿名模塊中,這一點請注意.

    最後,介紹默認打開的命名空間.包括F#在內的所有.Net開發語言都自動引用mscorlib.dll,F#更進一步地自動引用了FSharp.Core.dll.由於引用了該dll,F#程序執行時自動打開以下這些命名空間。

自動打開的命名空間
open Microsoft.FSharp
open Microsoft.FSharp.Core
open Microsoft.FSharp.Core.LanguagePrimitives
open Microsoft.FSharp.Core.Operators
open Microsoft.FSharp.Text
open Microsoft.FSharp.Collections
open Microsoft.FSharp.Core.Pervasives
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章