F#与C#/java/C++的代码区域划分有很大的不同,它是靠行缩进来区别不同的代码作用域的。F#编译器编译文件的顺序是垂直从上到下,就如之前说的F#代码文件都是有上下顺序的,如图:
这个项目下有两个文件,如果"Program.fs"想要引用"Helper.fs"里的代码,那么"Helper.fs"文件必须在"Program.fs"上面,不然会出现未定义错误。这里可以通过选中该文件,然后用"Alt+向上箭头"和"Alt+向下箭头"来上下调整文件顺序。[注意:多个文件时,如果要定义Main函数或入口,这必须定义在最下面文件的底部。]
这里顺便介绍下F#里的几种代码文件:
- 以fs后缀结尾的文件是正式的代码文件,就如C#中的cs文件及C++中的cpp文件
- 以fsi后缀结尾的文件是签名文件,就是把函数的定义声明在该文件里,类似于C++的头文件。
- 以fsx后缀结尾的文件是脚本文件,可以脱离VS单独运行,用F# Interactive(fsi.exe)运行。可以右键该文件,选择"Run With F# Interactive"直接运行。而在项目工程里fsx文件也遵循垂直编译原则。不过要注意的是fsx与fs文件是不相同的,即不能相互引用。
接下来说下同文件里的代码划分:
例如下图:
首先最外层的是该文件中缩进最少的行,如这里的"PrintColors"函数,其次是在该行下面有更多间距的缩进就是其函数体, 从这里可以看出MAX、start、reduce这三个变量和紧接着的for循环代码块是同一层的,然后是for循环里面的代码继续缩进表示接下来的代码都是包含在for循环中的,如果代码不想包含在for循环里,可以使用同MAX相同的缩进回到上一层。
这里变量的作用域是该变量接下来的代码(缩进间距大于或等于该变量声明行)直到碰到缩进间距小于它自己的范围。
在一个文件中最少的缩进(或顶格)行是最外面层,然后在里面用不同缩进表示不同层次,这就像C#里类里包含方法,方法里再包含代码一样。
由于缩进的间距是空行不易识别,虽然惯例是用tab(默认4格空格)进行一层缩进。下面是使用前面介绍过的一个很便利的工具""后的代码:
非常清晰的显示出了代码的层次。
module与namespace
module一般用于一个功能的代码块,namespace可以包含多个module. 例如下面代码: Helper.fs:module Utilities /// This is a sample value let sampleValue = 7 + 10 /// This is a sample function let sampleFunction argument1 argument2 = argument1 + argument2 Program.fs:open Utilities // These are some sample values. let sample1 = sampleFunction 4 12namesapce中包含多个module:namespace sample
module sample1 = let sampledata = 1 let sampleFun argument1 argument2 = argument1 + argument2module sample2 = let sampledata = 1 let sampleFun argument1 argument2 = argument1 + argument2 外面引用: sample.sample2.sampleFun 3 4 或 open sample.sample2 sampleFun 3 4