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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值