3.1 类型系统

主要表现 Ruby Javascript Go Lua
强弱分类 是否容忍隐式类型转换 强类型 弱类型 强类型 弱类型
动静分类 变量类型是否可变 动态类型 动态类型 静态类型 动态类型

语言类型系统有强类型/弱类型, 静态类型/动态类型 2种维度, 概念上往往容易混淆.


学术定义

Program Errors

  • trapped errors: 导致程序终止执行, 如除0, Java中数组越界访问
  • untrapped errors: 出错后继续执行, 但可能出现任意行为. 如C里的缓冲区溢出, Jump到错误地址

Forbidden Behaviours

语言设计时,可以定义一组forbidden behaviors: 它必须包括所有untrapped errors, 但可能包含trapped errors.

behaved

  • well behaved: 如果程序执行不可能出现forbidden behaviors, 则为well behaved.(红色区域外)
  • ill behaved: 否则为ill behaved. (只要出现红色区域)
Program Errors
Figure: Program Errors

类型定义

  • 强类型: 所有程序都是well behaved, 即不可能出现forbidden behaviors(无红色区域)

    表现形式: 偏向于不容忍隐式类型转换

  • 弱类型: 否则为弱类型, 可能出现forbidden behaviors(只要出现红色区域)

    表现形式: 偏向于容忍隐式类型转换

  • 静态类型: 编译时拒绝ill behaved (编译时排除红色程序)

    表现形式: 编译的时候就知道每一个变量的类型, 因为类型错误而不能做的事情是语法错误

  • 动态类型: 运行时拒绝ill behaved (运行时排除红色程序)

    表现形式: 编译的时候不知道每一个变量的类型, 因为类型错误而不能做的事情是运行时错误

  • type safe: 所有程序都在黄框以外.

动态, 静态类型和强弱类型没有对应关系, 比如动态类型Ruby, Python是强类型语言.

静态/动态

静态类型的特点是变量在编译时确定了类型, 无法改变, 如C, Go, Java等:

// go
var a = 3
a = "fox" //报错

而动态类型中变量类型可以改变:

# ruby
x = 3
x = "zhong"
x = :fox

强类型/弱类型

强类型偏向于不容忍隐式类型转换, 以下例子可以说明ruby是强类型:

# ruby
x = '3'
y = 3
x + y # TypeError: no implicit conversion of Fixnum into String

Ruby 允许你反复修改一个变量的类型(动态类型), 但是如果你在一个语句中混合多种类型, Ruby并不情愿去猜测你想表达什么意思, 猜测太复杂, 而且有风险(有可能猜错, 比如上例中, 用户是期望返回「33」还是「6」呢), 所以Ruby直接返回错误.注1

而弱类型如C, Javascript, Lua等偏向于容忍隐式类型转换:

// javascript
var x = '3';
var y = 3;
x + y // '33'
-- lua
x = '3'
y = 3
x + y # 6

从上面的例子中可以看出来, 两种弱类型语言对混合类型运算的「猜测」不一样, 如果你经常会跨语言开发, 依赖这些隐式类型转换将可能造成潜在的bug.

最佳实践: 隐式类型转换造成的问题远大于它带来的好处, 不要依赖它.

语言类型坐标

语言类型坐标
Figure: 语言类型坐标

可以看出的趋势, 较新的语言, 逐渐都放弃了Weak type, 更多的采用Strong type.


参考资料


注1. Ruby中也存在一定的隐式类型转换, 见类型转换

results matching ""

    No results matching ""