编程语言入门/类型定义
绝大多数编程语言都处理类型化的值,例如整数、布尔值、实数、人员、车辆等。然而,也有一些编程语言根本没有类型。这些编程语言往往非常简单。这方面的典型例子是核心lambda演算和Brainfuck。还有一些编程语言拥有非常原始的类型系统。例如,x86汇编允许将浮点数、整数和地址存储到同一个寄存器中。在这种情况下,用于处理寄存器的特定指令决定了要考虑的数据类型。例如,x86汇编有一个subl指令来执行整数减法,还有另一个指令fsubl,用来减去浮点值。再比如,BCPL只有一种数据类型,即一个字。不同的操作将每个字视为不同的类型。然而,大多数编程语言都有更复杂的类型,我们将在这章中讨论这些类型系统。
我们现在应该回答的最重要的问题是“什么是数据类型”。我们可以通过结合两个概念来描述数据类型
- 值:本质上,类型是一组值。例如,许多编程语言中都有的布尔数据类型就是一个包含两个元素的集合:真和假。这些集合中有一些包含有限数量的元素,而另一些则是无限的。在Java中,整数数据类型是一个包含232个元素的集合;然而,字符串数据类型是一个包含无限数量元素的集合。
- 操作:并非所有操作都可以在所有数据类型上应用。例如,我们可以对两个数字类型求和;但是,在大多数编程语言中,对两个布尔值求和是没有意义的。在x86汇编和BCPL中,操作区分内存位置的类型和其它位置的类型。
类型的存在是为了让开发者能够在程序中表示现实世界中的实体。但是,类型并不是它们所表示的实体。例如,Java中的整数类型代表从-231到231-1的数字。更大的数字无法表示。如果我们尝试给Java中的整数赋值,比如231,那么我们得到-231。之所以发生这种情况,是因为Java只允许我们表示任何二进制整数的31个最低位。
类型在许多方面都是有用的。类型如此重要的事实证明了这一点,如今几乎所有编程语言都使用类型,无论是静态类型还是运行时类型。在使类型如此重要的众多因素中,我们提到了
- 效率:由于不同的类型可以使用不同的方式表示,因此运行时环境可以为每种表示选择最有效的替代方案。
- 正确性:类型可以防止程序进入未定义状态。例如,如果将一个整数和一个浮点数相加的结果是未定义的,那么运行时环境可以在此操作可能发生时触发一个异常。
- 文档:类型是一种文档形式。例如,如果一个程序员知道一个给定变量是一个整数,那么他或她就对该变量了解很多信息。例如,程序员知道这个变量可以是算术运算的目标。程序员也知道分配该变量需要多少内存。此外,与对编译器毫无意义的简单注释相反,类型是编译器可以检查的文档形式。
类型是一个引人入胜的主题,因为它们根据许多不同的维度对编程语言进行分类。三个最重要的维度是
- 静态类型与动态类型。
- 强类型与弱类型。
- 结构类型与名义类型。
在任何编程语言中,都有两种主要的类型类别:基本类型和构造类型。基本类型是原子的,也就是说,它们不是由其它类型的组合形成的。构造类型或复合类型,顾名思义,是由其它类型组成的,这些类型可以是基本类型,也可以是复合类型。在本章的剩余部分,我们将展示每种类型家族的例子。