■ 模块
模块是指将定义进行统一汇总并赋予名称的功能。由于只将有关联的定义进行统一汇总,所以可以提高代码块的独立性。虽然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;; |
上例中定义了a,b,c三个模块。访问模块中定义好的元素时需要象上例中那样加上点符号。
//类型的定义。模块名当然可以为大写字母 |
上例为定义类型,异常,省略名称的例子.
接下来,可以定义复合模块.
module Mix = begin |
同时,模块可以嵌套。
module A = begin |
对于模块,虽然进行访问时必须加上点符号,但是在比较麻烦的时候,可以对模块进行open。
module A = begin |
在上例中定义了模块A,由于对A模块进行了open,所以访问A模块中的a元素时可以不加点符号。
接下来,可以在模块中直接使用open,这种情况下,模块内的open不会影响到模块之外。
module A = begin |
一般,不针对List模块进行open,但是,在模块A内部即使对List进行了open操作,也不会对模块外产生任何影响,这种方法是可以使用的。
更进一步来说,可以给模块添加自动open的AutoOpen属性(Microsoft.FSharp.Core.AutoOpenAttribute)。下例中将模块进行嵌套并执行AutoOpen。
#light "off" |
可以确认加了AutoOpen属性的模块在被访问时可以不加模块名而直接访问。
■ 命名空间
当程序的规模大到一定程度时,会产生函数或变量名互相冲突的问题。为了解决这类问题,可以考虑使用命名空间。在.Net中定义了各种类库,定义了不同语言的Microsoft.FSharp,Microsoft.CSharp,Microsoft.VisualBasic等很多命名空间。
命名空间的定义形式基本如下:
-
命名空间的定义
-
封装文件:= [命名空间的定义]*
命名空间的定义:=
| namespace 命名空间名 顶级模块的定义
| module 模块名 模块的元素
| 模块的元素
举例如下
namespace test |
这个例子中定义了命名空间test与其中的模块A。
同样也可以对命名空间进行open。
//file1.fs |
在这个例子中,在file1.fs文件中定义了命名空间test并在main.fs文件中对test命名空间进行open。另外,应该要注意的是,如果首先编译了main.fs文件,则对file1.fs文件中的命名空间进行的open操作就不能正常执行了。关于这一点,请参考编译器的使用方法一节中的程序装载顺序部分。
使用命名空间时,与使用模块不同的是:
1.不能在定义命名空间的时候定义值(let等等)。
2.不能在命名空间的定义前书写针对编译器进行的指示代码。
3.由于上述因素,不能对命名空间进行AutoOpen。
4.命名空间不能被嵌套。
5.命名空间没有省略名称。
针对前面命名空间部分中的第一个例子,以下写法会引起编译错误。
namespace A |
另外如前所述,命名空间不能被嵌套使用。虽然默认打开的命名空间(后文详述)表面上看上去像是嵌套空间,但实际上是通过如下方式被打开的。
namespace N |
上例中的定义可以被象下例中所示地分阶段打开。但是,1.9.6.2版本后不推荐这种打开方式。
open N; |
这是因为,在F#中,原本是允许如下所示的打开方法的,但是现在推荐使用命名空间的完全名称的打开方式。
open System |
另外,在命名空间的定义部分的第2,3行中的函数分别被称为具名函数/匿名函数.因此,可以象下例那样不加begin/end语句而直接定义模块.
module A |
另外,迄今为止没有定义模块而直接书写的代码都在匿名模块中,这一点请注意.
最后,介绍默认打开的命名空间.包括F#在内的所有.Net开发语言都自动引用mscorlib.dll,F#更进一步地自动引用了FSharp.Core.dll.由于引用了该dll,F#程序执行时自动打开以下这些命名空间。
open Microsoft.FSharp |