一文辨析编程语言的强类型与弱类型、静态类型与动态类型
目前的一些人似乎存在一个误解,而且是普遍地存在这个误解,包括我以前也有一点:总是分不清强弱类型、静动态类型的区别。确切地说,这两对反义词单独分辨还好懂,合在一起就让人分不清。
今天我就来讨论一下。
定义
强类型与静态类型、弱类型与动态类型并非绑死的。事实上,这是完全不同的两组概念。
动/静态类型
静态类型
变量类型是固定的,不能改变。
动态类型
变量本身是没有类型的,只有对象才有类型。
动静类型举例
Python(动态类型)
在Python中变量类型可以随意改变,类型的属性和方法也可以随意改变。类型标注不是强制静态类型的。
a:int=0 # 类型标注可选
a="Now I'm a string."
a=True
a=[1,2,3]
a=(1,2,3)
a={1,2,3}
a={1:2,3:4}
Rust(静态类型)
假如你不使用重影覆盖下面的a
变量,它就一直是i32
类型。
fn main(){let mut a=1;// a='a'; // 报错// a=1.1; // 报错
}
强/弱类型
强类型
对象类型不允许隐式类型转换的编程语言。
弱类型
对象类型可以隐式转换的语言。
强类型和弱类型是一个递变的光谱,没有绝对的弱/强类型。
强弱类型举例
Python(强类型)
在Python shell中输入:
>>>1+'a'
Traceback (most recent call last):File "<pyshell#0>", line 1, in <module>1+'a'
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>>
>>>"abc"+1
Traceback (most recent call last):File "<pyshell#0>", line 1, in <module>"abc"+1
TypeError: can only concatenate str (not "int") to str
在Python中,字符串和数字不得直接相加,但是int和float、int和bool可以直接相加而不报错。
要想不报错得这样:
>>>1+int("1")
2
>>>1+float("1")
2.0
>>>str(1)+"1"
'11'
>>>1+eval("1")
2
C(弱类型)
#include<stdio.h>
int main(){char a='a';int b=a; // b=97 int* pb=&b;unsigned long* pc=pb;signed char* pd=pb;unsigned char f=*pd;
}
以上莫名其妙的代码是不会报错的。而且你会得到一些匪夷所思的结果。
JavaScript (弱类型)
JavaScript中会有许多更诡异的事情出现。
let a = "100"
let b = a-5 // 95,Python会报错,但是JS不会
let c = a+'5' // "105"
let d = [1,2]+[3,4] // "1,23,4"
PHP也类似,不愧是世界上最好的编程语言。
总结
静态类型和动态类型到底哪种类型好呢?
有的人注重可维护性,认为静态类型远远优于动态类型。(在《半小时漫画计算机》中,上帝的秤上动态类型只有3斤,而静态类型有5斤,我认为这显然有失偏颇)
《黑客与画家》的作者Paul Graham是Lisp的忠实粉丝,他说“在我认识的所有黑客中,没有一个是喜欢用静态类型语言编程的”“代码应该成为你思考的工具,而不是你表达的工具”等话,表现动态类型赋予黑客的创造力。
但是我认为强类型总是比弱类型好一点。当然不排除有些人喜欢弱类型。但有时候弱类型语言造成的类型Bug会让人气急败坏。
列表如下:
交叉表
类型特性 | 强类型 | 弱类型 |
---|---|---|
静态类型 | Java,D,Rust,MoonBit | C,TypeScript |
动态类型 | LISP,Python | JavaScript,PHP |
语言表
下表列出了大部分常见语言(及部分小众语言)的类型性质。
语言 | 动/静 | 强/弱 |
---|---|---|
LISP | 动态类型 | 强类型 |
C | 静态类型 | 弱类型(强于JS) |
C++ | 静态类型 | 中弱类型(强于C) |
Python | 动态类型 | 强类型 |
Java | 静态类型 | 强类型 |
JavaScript | 动态类型 | 弱类型 |
Lua | 动态类型 | 中弱类型 |
Python | 动态类型 | 强类型 |
Java | 静态类型 | 强类型 |
JavaScript | 动态类型 | 弱类型 |
C# | 静态类型 | 强类型 |
D | 静态类型 | 强类型 |
PHP | 动态类型 | 弱类型 |
Go | 静态类型 | 强类型 |
TypeScript | 静态类型(为主) | 弱类型 |
Rust | 静态类型 | 强类型(最强) |
Zig | 静态类型 | 强类型 |
Mojo | 都有 | 强类型 |
MoonBit | 静态类型 | 强类型 |
总结:即使是两对简单的概念,也很容易弄错。当你看到有某些书说“Dart是强类型,变量类型无法改变”之类的话,其实就是在犯这个错误。希望通过这篇文章,读者能明确分辨出两种语言类型特性的不同。谢谢大家。