为什么需要类型
在底层的硬件和机器代码级别,程序逻辑(代码)及其操作的数据是用位来展示的。在这个级别,代码和数据没有区别,所以当系统误将代码当成数据,或将数据当成代码时,就很容易发生错误。这些错误可能导致系统崩溃,也可能导致严重的安全漏洞,攻击者利用这些漏洞,让系统把他们的输入数据当作代码执行。(在 JavaScript 中的 eval()函数就是一个宽松代码解释的例子,它将一个字符串视为代码执行)
类型为数据赋予了意义,告诉软件在给定上下文中如何解释给定位序列,使其保留期望的意义。
类型还限制了一个变量可以接受的有效值的集合。可以保证代码再运行时不会出现无效值,从而避免出现各种错误。
类型和类型系统的定义
- 类型:类型是对数据做的一种分类,定义了能够对数据执行的操作、数据的意义,以及允许数据接受的值的集合。编译器和运行时会检查类型,以确保数据的完整性,实施访问限制,以及按照开发人员的意图来解释数据。
- 类型系统:类型系统是一组规则,为编程语言的元素分配和实施类型。这些元素可以是变量、函数和其他高级结构。类型系统通过两种方式分配类型:程序员在代码中指定类型,或者类型系统根据上下文,隐式推断出某个元素的类型。类型系统允许在类型之间进行某些转换,而阻止其他类型的转换。
- 类型检查 :类型检查确保遵守类型系统的规则。编译器在转换代码时进行类型检查,而运行时在执行代码时进行类型检查。编译器中负责实施类型规则的组件叫做类型检查器。
类型系统的优点
类型的主要优点在于正确性、不可变性、封装、可组合性和可读性。这些优点是优秀软件设计和行为的根本特性。
- 正确性:正确的代码指的是行为符合规范,能够产生期望的结果,并且不会导致运行时错误或崩溃的代码。
- 不可变性:系统正处于通过状态,而在通过状态中我们在一个好的状态中时,能够保持该状态并且维持该状态下的一些部分不变,就减少了出错的概率。
- 封装:封装指的是隐藏代码内部机制的能力,代码可以是函数、类或者模块。
- 可组合性:将独立的组件组合起来,能够得到模块化系统,并减少需要维护的代码。随着代码模块和组件数量的增加,可组合性会变得很重要。
- 可读性:类型能够清晰表明函数期望得到什么实参,泛型算法的先决条件是什么,类实现了哪个接口,等等。这些信息很有用,因为它允许我们单独思考可读的代码:只需查看定义,我们就能够比较轻松地理解代码的工作方式,而不必去源代码中查看调用者和被调用者。
类型系统的类型
动态类型和静态类型
- 动态类型:动态类型不会在编译时施加任何类型约束。
- 静态类型:静态类型在编译时执行类型检查,所以试图传入错误类型的实参会导致编译错误。
弱类型与强类型
- 强类型:强类型系统只会在其认为安全的转换提供有限的隐式转换。
- 弱类型:弱类型系统会隐式地尝试将值从其实际类型转换为使用该值时期望的类型。