5.5.1.1 类型批注、动作和语句块(TYPE ANNOTATIONS, ACTIONS, AND STATEMENT BLOCKS)

来源:互联网 发布:js指定浏览器打开网页 编辑:程序博客网 时间:2024/05/16 04:47

5.5.1.1 类型批注、动作和语句块(TYPE ANNOTATIONS, ACTIONS, AND STATEMENT BLOCKS)

 

在前面的示例中,我们没有显式指定参数类型。这在 F# 中是正常行为,因为,类型推断能力非常强大,而且,在前面的示例中,有足够的线索能推断出类型。在 C# 中,是另一种方式,也相当重要:

 

Func toStr1 = num => num.ToString();

Func toStr2 = (int num) =>num.ToString();

 

两行代码基本相同,唯一区别在于,第二行显式指定 num 参数的类型。两行都是正确的,那么,C# 如何知第一行中 num 的类型呢?答案是,类型来自变量的声明。它知道,Func < int, string> 是一个委托,取一个整数作为参数值,因此,推断 num 的类型应该为整数。

在 C# 中,很少需要显式参数类型;C# 通常能够推断出类型,但不管怎样,都不能使用 var 关键字声明 lambda 函数。有一个例外情况,使用 lambda 函数作为特定泛型方法的参数值。即使在 F# 中,我们偶尔也可能需要给编译器以更多的信息,即,使用类型批注(type annotations)。清单 5.16 显示了带有类型批注的 lambda 函数,显式声明参数的类型。

 

清单 5.16 高级 lambda 函数 (F# Interactive, C#)

// F# version of the code (using F#Interactive)

> let sayHello =

   (fun(str:string) –>  [1]  类型批注

     letmsg = str.Insert(0, "Hello ")

     Console.WriteLine(msg)

   )

val sayHello : string –> unit

 

// C# version of the code

Action sayHello =  [2]  动作委托

  str=> {    [3]  语句块语法

    varmsg = str.Insert(0, "Hello ");

    Console.WriteLine(msg);

};

 

这个示例展示了几件重要的事情。第一件是在 F# 中使用类型批注[1]。在 lambda 函数中的类型批注,其语法与 F# 代码中的其他任何地方都一样。在这里,我们之所以要使用它的原因是,调用值 str 的实例方法 Insert,它不能给编译器提供足够的信息来确定值的类型。

另一件值得注意的事情是,lambda 函数体不仅仅是表达式。在 F# 中,我们添加了一个 let 绑定,把整个 lambda 函数括在括号中。在 C# 版本中,我们添加了一个变量声明,改变语法为使用语句块(statement block)。语句块,是括在大括号内的lambda 函数体[3],能够在函数体内有多条语句。要从使用语句块的lambda 函数返回结果,必须使用 return 关键字,就如同从方法返回结果一样。

在这个示例中,lambda 函数不返回结果。在 F# 中,unit 是一个普通类型,推导出的函数签名是 string -> unit。原则上,这就是一个普通的 F# 函数,结果返回 unit 值(即,什么也没有);但在 C# 中,不能写成 Func<string, void>,因为,void 不是真正的类型。为此,C#有另外一族委托类型,称为Action(动作)[2],表示没有返回类型的 lambda 函数。Action 和 Func 委托非常有用,对应于 F# 中的函数类型,因此,我们需要详细了解函数值的类型。

0 0
原创粉丝点击