F#基础教程 unit类型

前言:

     正如你在第三章看到的,你可以使用F#作为纯函数编程。然而有些问题,最明显的是I/O,没有状态的改变几乎是不可能的。F#不要求你的程序是一个无状态的模式。它允许你使用可变(mutable)标识符,其值可以随时间而改变。F#还支持命令式编程的其他结构。在第三章你已经看到一些例子。任何输出到控制台的例子都包含一些命令式代码在函数式代码旁。在本章中,我们将探索这些结构,和更多其他结构,及其更多细节。

    首先,先了解F#的unit类型,这种特殊的类型意味着“no value”,是命令式编程特有的。接下来,你将看到F#里处理可变状态的一些方法,也就是说,可以随时间改变值的类型。这些都是ref类型,可变记录类型和数组。最后,你将看到使用.NET库。包括调用静态方法,创建对象和其成员的方法,使用特殊成员如索引和事件,并使用F#的|>操作符,非常方便的处理与.NET库的交互。

正文:

    任何不接收值或返回值的函数是unit类型,这类似在C#中的void类型和CLR中的System.Void。对于函数式程序员,一个函数不接收值或返回值似乎没有任何意义,因为如果它不接收或返回一个值,它什么都不做。在现实的世界中,你知道存在副作用,因此,即使一个函数接收或返回nothing,你知道它仍然有它的用途。unit类型代表一个常量,一对括号“()”。这意味着,每当你想要一个不接收值或返回值的函数,你只要在()里放入代码:

#light
let main() =
    ()

    在这个例子中,main是一个函数,因为你把括号放在标识符后,成为其参数。如果没有这一点,将意味着main不是一个函数而仅是一个非函数的值,如你所知,所有函数都是值,但在这里,一个函数和一个非函数的值之间的差别是重要的。如果main是一个非函数的值,在它里面的表达式将只计算一次。然而它是一个函数,表达式将在每次调用时计算一次。

注意:仅仅因为一个函数的名字是main并不意味着它是程序的入口点并自动执行。如果你想要main函数执行,那么你需要在源文件最后添加对mian()的调用。第六章将详细介绍如何定义F#程序的入口点。

    同样,放置在等号后的(),告诉编译器,你将返回nothing。通常情况下,你需要放置一些东西在等号和空括号之间,或空函数;为了保持简单,我们将留下这个空函数。现在可以看到使用fsc -i开关的main类型;结果如下,正如你所看到的,main类型是一个函数,接收unit并返回unit类型的值。

val main : unit –> unit

    因为编译器知道该函数不返回任何东西,你可以使用一些特殊的命令式结构。调用这个函数,你可以使用let关键字,然后是一对括号和等号。这是let关键字的一种特殊用法,意味着“调用一个不返回值函数”。另外,你可以简单的只调用函数,不需要任何多余的关键字。

#light
let () = main()
// -- or --
main()

    同样,你可以链接一些返回unit的函数到一个函数里---确保他们有相同的缩进。下一个例子显示了几个print_endline函数的链接,打印文本到控制台:

let poem() =
    print_endline "I wandered lonely as a cloud"
    print_endline "That floats on high o'er vales and hills,"
    print_endline "When all at once I saw a crowd,"
    print_endline "A host, of golden daffodils"
poem()

    这种方式只可以使用返回unit类型的函数,并不完全正确;然而,使用其它类型而不是unit会产生一个警告,这点是大多数程序员都希望避免的。因此,为了避免这种情况,有时转换一个不返回一个值的函数到一个unit类型函数非常有用的,因为它有一个副作用。在使用F#库编写F#时这相当罕见,但在使用.NET库编写F#时则较为常见。

    下面的例子演示如果把一个返回一个值的函数链接到一个返回unit的函数,或者说如果用返回unit的函数调用一个返回一个值的函数:

#light
let getShorty() = "shorty"
let _ = getShorty()
// -- or --
ignore(getShorty())
// -- or --
getShorty() |> ignore

    首先,你定义函数getShorty,返回一个字符串。现在想象一下,由于某种原因,你想调用这个函数但忽略其返回。接下来的两行演示做到这一点的不同方式。首先,你可以使用let表达式,用下划线字符(_)在标识符的地方,下划线告诉编译器,你对这个值不感兴趣。第二方法,是上面的过程被包裹为一个函数,ignore,这在F#基础库里定义。最后一行显示调用ignore的另一种方法,使用pass-forward操作符来传递getShorty() 的结果给ignore函数。说明pass-forward操作符在”|>操作符”一节。(pass-forward意思即通过、向前。也附带传递的意思)

posted @ 2011-12-07 22:29  银河系漫游指南  阅读(761)  评论(0编辑  收藏  举报