2.4.1 C# 和 F# 中的类型推断

2.4.1 C# 和 F# 中的类型推断

 

    大多数的类型有一个简单的名称,例如 int 或 Random,只有很少一部分需要类型推断,因为手写类型名称并不困难。C# 2.0 支持泛型,因此,可以构建更复杂的类型。在函数语言中的类型,像 F#,是相当复杂的,尤其是把函数当作值使用,因此,还必须有一种类型来表示函数。

    对局部变量的类型推断一个简单形式,现在 C# 3.0 中是可用的。在早期版本的 C# 中声明一个局部变量,必须显式指定类型。在 C# 3.0 中,可以通常用一个新关键字 var 代替类型名称,让我们来看几个基本的示例:

 

var num = 10;
var str = "Hello world!";

 

    第一行声明的变量 num,并初始化其值为 10。编译器可以很容易推断出表达式的右侧是 int 类型,所以它知道变量的类型也必须是 int。注意,此代码的意思与你明确写出类型是完全相同样的。在编译期间,C# 编译器用实际类型替换 var,所以,在运行时没有额外的工作要做。正如我们刚才所说的,在处理复杂泛类型时,这是特别有用。例如,我们可以编写下面的代码:

 

var dict = new Dictionary<string, List&lt;IComparable&lt;int>&gt;&gt;();

 

    没有 var 关键字时,就必须在一行上两次指定类型:

    ■ 在声明变量时

    ■ 创建 Dictionary 类的实例时

    在 C# 中的类型推断仅限于本地变量声明。F# 中,通常根本不要写出任何类型。如果 F# 的类型推断无法推断出某种类型,才需要显式指定类型,但相对很少出现这种情况。

    为了给你更好的这是如何工作的概念,清单 2.5 显示了一个简单的函数,取两个参数,相加,用 String.Format 方法将结果格式化。该清单首先显示了有效的 F# 代码,然后,你可以编写方式它,在 C# 中,如果隐式类型化被扩展,允许你在其他地方使用 var 关键字。

 

Listing 2.5 Implementing methods with type inference

 

let add a b =
let res = a + b
String.Format("{0} + {1} = {2}", a, b, res)


var Add(var a, var b) {
var res = a + b;
return String.Format("{0} + {1} = {2}", a, b, res);
}

 

    正如你所看到的,F# 的语法被设计成,在这个源代码中根本不必写任何类型。在 pseudo-C# 版本中,我们使用 var 关键字代替任何类型,这(原则上)就是 F# 编译器看到的,当你输入这段代码时。如果你将此函数的代码粘贴到 F# Interactive时,它将正确处理, F# Interactive 将报告该函数限两个整数作为参数值,并返回一个字符串。让我们看看 F# 编译器是如何理解的。

    编译器的第一个线索是,我们要加的值 a 和 b。在 F# 中,我们可以用 + 相加任何数值类型或连接字符串,但如果编译器不知道是什么类型的值,它假定相加的是两个整数。从这单个表达式来看,编译器可以推断出 a 和 b 都是整数。使用这个信息,它可以找到 String.Format 方法的适当的重载,该方法返回字符串,因此,编译器可以推断出,add 函数的返回类型也是一个字符串。

    由于类型推理,我们可以避免很多错误,也能使用静态类型的所有其他好处(如,开发人员编写的代码时的提示),在大多数情况,类型被自动推断几乎是无价的。当使用 Visual Studio 中 的 F#,类型推断在后台运行,因此,当将鼠标悬停在鼠标指针覆盖的值上时,会立即看到其类型。背景编译也即时报告任何输入错误,所以,你会得到编写 C# 代码时的相同的体验。

    如果你曾经使用过从其他编程语言的类型,可能已经知道有一些基元类型 (如整数、字符,或浮点数),和由这些基元类型组成的复杂类型。函数语言有一组略有不同的复合类型。我们会在第 5 章详细讨论所有这些类型,但首先让我们探讨一个有趣的类型。

你可能感兴趣的:(F#,C#,职场,休闲,函数编程)