3、函数作用域
在F#中组织程序结构的方法有以下几种,使用类型 (type)来支持自定义数据类型,使用名称空间(namespace)来确保类型唯一,模块(module)则用来封装某一数据类型及其操作,而函数则封装了行为或业务逻辑。本文只简单介绍模块(module),其他内容将在下一主题中讨论。
函数是函数式语言中最基本的组成,是应用程序中具体业务逻辑的实现者,弄清其作用域非常必要。
在F#语言中,每一个源代码文件(本文仅指以.fs为扩展名的文件),其默认有一个以文件名首字母大写的模块名(module name),你在源代码中定义的常量、变量、类型、函数等其作用范围都在这个模块(module)中。
代码一:
Code
1(* 文件名:test.fs *)
2
3#light
4
5let c=10
6
7let mutable v=5.0
8
9let f c v=
10
11float c * v
12
13printfn "%.2f" (f c v)
14
15open System
16
17Console.ReadKey(true)
18
F#使用 (* *)来多行注释,//单行注释,代码一中定义的常量c,变量v以及函数f其作用范围默认为Test 模块中(module),注意代码假定源代码文件名为test.fs
本文以下讨论作用域均在模块范围以内,关于如何自定义模块,命名空间,以及多模块、命名空间之间如何访问等内容在下一主题中讨论
在一个模块中,我把函数以外的作用域称为顶级作用域,函数体内称为局部作用域,通常在静态语言中作用域指的是定义域,但在F#中作用域因为lambda表达式,更具体地说因为闭包(closure)而引入了运行时访问域的概念(我暂且这样称呼他)。
F#中顶级作用域中定义的标识符名称必须是唯一的。而在函数体内定义的标识符名称却可以重复定义,且后者隐藏前者。
在下面的代码二中,函数f外,顶级作用域定义的标识符有c,v,包括f。这三个标识符名称必须唯一,否则会编译出错。
代码二:
Code
1#light
2
3let c=10
4
5let mutable v=5.0
6
7let c="c" (*编译出错,值c重复定义 Duplicate define of value 'c'*)
8
9
但在函数体范围内却可以重复定义。