技术开发 频道

Visual Studio 2010 F#快速上手

  不可变性(Immutability)

  也许已经注意到,我一直使用“值(value)”来表示一个标识符(identifier),而不是“变量(variable)”。这是由于默认情况下,F#中的类型是不可变的(immutable),也就是说,一经创建即不可修改。看起来这是一个很大的限制,但是不可变性可以避免某种类型的bug。另外,不可变的数据天然地具备线程安全的特性,这意味着您无需在处理并行情况时担心同步锁的发生。

  如果您确实需要修改数据,可使用F#的mutable关键字,它会创建一个变量(而不是值)。我们可以通过左箭头操作符(<-)来修改变量的值。

> let mutable x = "the original value.";;
val mutable x :
string
> printfn "x's value is '%s'" x;;
x
's value is 'the original value.'
val it : unit = ()

> x <- "the new one.";;
val it : unit
= ()
> printfn "x's value is now '%s'" x;;
x
's value is now 'the new one.'
val it : unit = ()

  引用值(Reference values,Microsoft.FSharp.Core.Ref<_>)

  引用值是另一种表示可修改数据的方式。但它不是将变量存储在堆栈(stack),引用值其实是一个指向存储在堆(heap)上的变量的指针(pointer)。在F#中使用可修改的值时会有些限制(比如不可以在内部lambda表达式中使用)。而ref对象则可被安全地传递,因为它们是不可变的record值(只是它有一个可修改的字段)。

  使用引用值时,用“:=”赋一个新值,使用“!”进行解引用。

> let refCell = ref 42;;
val refCell :
int ref

> refCell := -1;;
val it : unit
= ()

> !refCell;;
val it :
int =1

  模块(Modules)

     在C#中所有一切都要属于相应的类。尽管在F#中,我们仍然可以用熟悉的方式声明标准的.NET类,但它也有模块的概念,模块是值、函数和类型的集合(可以对比一下命名空间,后者只能包含类型)。

  这也是我们能够访问“List.map”的原因。在F#库(FSharp.Core.dll)中,有一个名为“List”的模块,它包含了函数“map”。

  在快速开发的过程中,如果不需要花费时间去设计严格的面向对象类型体系,就可以采用模块来封装代码。要声明自己的模块,要使用module关键字。在下面的例子中,我们将为模块添加一个可修改的变量,该变量也是一个全局变量。

module ProgramSettings =
    let version
= "1.0.0.0"
    let debugMode
= ref false

module MyProgram
=
    
do printfn "Version %s" ProgramSettings.version
    open ProgramSettings
    debugMode :
= true

  元组(Tuples)

  元组(tuple,发音为‘two-pull’)表示值的有序集合,而这些值可看作一个整体。按传统的方式,如果您要传递一组相关的值,需要创建结构(struct)或类(class),或者还需要“out”参数。使用元组我们可以将相关的值组织起来,同时并不需要引入新的类型。

  要定义一个元组,只要将一组值用逗号分隔,并用圆括号把它们括起来即可。

> let tuple = (1, false, "text");;
val tuple :
int * bool * string

> let getNumberInfo (x : int) = (x, x.ToString(), x * x);;
val getNumberInfo :
int -> int * string * int

> getNumberInfo 42;;
val it :
int * string * int = (42, "42", 1764)

  函数甚至可以接受元组为参数:

> let printBlogInfo (owner, title, url) = printfn "%s's blog [%s] is online at '%s'" owner title url;;
val printBlogInfo :
string * string * string -> unit

> let myBlog = ("Chris", "Completely Unique View", "http://blogs.msdn.com/chrsmith");;
val myBlog :
string * string * string

> printBlogInfo myBlog;;
Chris
's blog [Completely Unique View] is online at 'http://blogs.msdn.com/chrsmith'
val it : unit = ()

  函数柯里化(Function Currying)

  F#提供的一个新奇的特性是可以只接受参数的一个子集,而接受部分参数的结果则是一个新的函数。这就是所谓的“函数柯里化”。比如,假设有一个函数接受3个整数,返回它们的和。我们可以只传入第一个参数,假设值为10,这样我们就可以说将原来的函数柯里化了,而它会返回一个新的函数——新函数接受两个整数,返回它们与10的和。

> let addThree x y z = x + y + z;;
val addThree :
int -> int -> int -> int

> let addTwo x y = addThree 10 x y;;
val addTwo :
int -> int -> int

> addTwo 1 1;;
val it :
int = 12
0