动态、静态类型与强弱类型

简单解释

编译时就知道变量类型的是静态类型,运行时才知道一个变量类型的叫做动态类型

比如:编译器在将 int age = 18; 这段代码编译的时候就会把 age 的类型确定,换言之,你不能对他进行除以 0 的操作等等,因为类型本身就定义了可操作的集合;但是像 C++ 里常见的 auto ite = vec.iterator(); 这种也属于静态类型,这种叫做类型推导,通过已知的类型在编译时期推导出不知道的变量的类型。在静态类型语言中对一个变量做该变量类型所不允许的操作会报出语法错误。

但是像 var name = student.getName(); 这行 JavaScript 代码就是动态类型的,因为这行代码只有在被执行的时候才知道 name 是字符串类型的,甚至是 null 或 undefined 类型。你也没办法进行类型推导,因为 student.getName 函数签名根本不包含返回值类型信息。在动态类型中对一个变量做该变量类型所不允许的操作会报出运行时错误。

不允许隐式转换的是强类型,允许隐式转换的是弱类型

比如:在 Python 中进行 '666' / 2 你会得到一个类型错误,这是因为强类型语言中是不允许隐式转换的,而在 JavaScript 中进行 '666' / 2 你会得到整数 333,这是因为在执行运算的时候字符串 '666' 先被转换成整数 666,然后再进行除法运算。

复杂解释

需要先介绍一些基本概念:

  • Program Errors(程序错误)
    • trapped errors: 导致程序终止执行(程序意识到出错,使用对应的错误处理机制),如除 0,Java 中数组越界访问。
    • untrapped errors: 程序出错后继续执行(其实并不一定保证继续执行,程序本身并不知道出错,也没有对应的错误处理机制),如 C 语言里的缓冲区溢出,jmp 到错误地址。
  • Forbidden Behaviors(禁止行为)
    • 程序在设计的时候会定义一组 forbidden behaviors,包括了所有的 untrapped errors,可能包括 trapped errors
  • Well behaved、ill behaved
    • well behaved: 如果程序的执行不可能出现 forbidden behaviors,则称为 well behaved
    • ill behaved: 只要有可能出现 forbidden behaviors,则称为 ill behaved

他们之间的关系可以用下图来表达:

behaviors

从图中可以看出,绿色的 program 表示所有程序(所有程序,你能想到和不能想到的),error 表示出错的程序,error 不仅仅包括 trapped erroruntrapped error

根据图我们可以严格的定义动态类型、静态类型;强类型、弱类型:

  • 强类型:如果一门语言写出来的程序在红色矩形外部,则这门语言是强类型的,也就是上面说的 well behaved
  • 弱类型:如果一门语言写出来的程序可能在红色矩形内部,则这门语言是弱类型的,也就是上面说的 ill behaved
  • 静态类型:一门语言在编译时排除可能出现在红色矩形内的情况(通过语法报错),则这门语言是静态类型的。
  • 动态类型:一门语言在运行时排除可能出现在红色矩形内的情况(通过运行时报错,但如果是弱类型可能会触发 untrapped error,比如隐式转换,使得程序看起来似乎是正常运行的),则这门语言是动态类型的。

举例

在 Python 中执行 test = '666' / 3 你会在运行时得到一个 TypeError 错误,相当于运行时排除了 untrapped error,因此 Python 是动态类型,强类型语言。

在 JavaScript 中执行 var test = '666' / 3' 你会发现 test 的值变成了 222,因为这里发生了隐式转换,因此 JavaScript 是动态类型,弱类型的。更为夸张的是 [] == ![] 这样的代码在 JavaScript 中返回的是 true,这里是具体的原因

在 Java 中执行 int[] arr = new int[10]; arr[0] = '666' / 3; 你会在编译时期得到一个语法错误,这说明 Java 是静态类型的,执行 int[] arr = new int[10]; arr[11] = 3; 你会在运行时得到数组越界的错误(trapped error),这说明 Java 通过自身的类型系统排除了 untrapped error,因此 Java 是强类型的。

而 C 与 Java 类似,也是静态类型的,但是对于 int test[] = { 1, 2, 3 }; test[4] = 5; 这样的代码 C 语言是没办法发现你的问题的,因此这是 untrapped error,因此我们说 C 是弱类型的。

语言类型的划分

typing

由于强类型语言一般需要在运行时运行一套类型检查系统,因此强类型语言的速度一般比弱类型要慢,动态类型也比静态类型慢,因此在上述所说的四种语言中执行的速度应该是 C > Java > JavaScript > Python。但是强类型,静态类型的语言写起来往往是最安全的。

参考