当前位置: 首页 > 文档资料 > larva 中文文档 >

动态和静态类型

优质
小牛编辑
138浏览
2023-12-01

一个机器或语言是用来计算的,根据计算机模型的定义,其操作的是存储器里的数据,就现在流行的用二进制实现的计算机中(曾出现过三进制计算机),数据本质都是0和1,但机器毕竟是为人服务的,解决的是现实问题,它操作的数据需要有现实的含义,所以基本上所有语言都有类型系统,即便是汇编和机器语言,也有整数和浮点的区别

类型系统是很复杂的理论,值得用一本厚书来写,好点的资料有《类型与程序设计语言》,但我没看懂,因为太抽象了。其实如果想实际做东西,也不用搞很深的理论,了解一些常见的即可,比如类型的动静态的区别

类型的动态和静态,一般是指变量和类似变量(属性、数组元素等)的类型是否确定,比如说,C语言就是静态类型的,一个变量必须定以后才能使用,而且使用时,它的值必须按照它的类型来参与运算,比如int64_t和double都是8字节,但同样的数据内容,表示的数字可能完全不同,一个指针虽然以uint的方式存储,但含义也是不同的,做赋值操作时,如果被赋值的左值的类型和赋予的值得类型不同,需要进行转换,如果不符合语言本身规定的转换规则(一般都很受限,比如只能short赋值给int,子类对象地址赋值给父类指针等,反过来不行),就会编译报错

静态类型的优点在于,很多东西在静态编译阶段就能确定了,比方说我们定义了一个结构体s,那么在对s取属性的时候,就可以根据地址偏移来进行,因为s的类型的各属性的布局是确定好的,这就提高了程序运行速度,也方便做各种代码优化,比如一个对象A a,调用a.f()的时候,就可以静态确定调用的是哪个函数,视情况inline;另外,程序员写代码的时候,编译器可以做更严格的检查,防止出现一些非预期的错误

动态类型就相反,语言的变量和类似变量没有自己的类型,这并不是说这种语言没有类型,数据都是有类型的,只是变量可以引用任何对象,使用的时候以当前的值为准,比如:

a = 123   
print a   
a = "hello"   
print a

a只是一个名字,两次输出的时候,会根据a当时关联的具体的值来判断如何做

因为变量没有类型,所以动态类型语言一般都省掉了声明过程,这样代码写起来会很省事,但相对的静态编译就检查不出太多错误,一个变量没有定义就使用这种错误都会在运行时抛出,不过,这个问题不仅是动态类型的问题,跟整体的动态性也有很大关系,后面再专门论述

静态类型的实现,一般来说只要实现基本类型即可(整数,浮点数,地址指针等),因为结构体、类等高级类型说到底还是由基本类型组成的,这些东西在编译后,一般都消失无踪,运行时只知道从xx位置拿一个xx数据,做数学运算,然后写回xx地址

动态类型的话,以python为例,一般是采用面向对象的方式实现,所有的数据都以对象的形式体现,并且继承于同一个基类object,因此,python代码可以认为所有变量的类型都是object,因为大家都是,所以类型定义就可以省了,比如

def f(a, b):   
    return a + b   
print f(1, 2)   
print f("hello", "world")

换成静态类型的伪代码大概就是:

object f(object a, object b)   
{   
    return a.add(b);   
}   
put(f(Int(1), Int(2)).toString())   
put(f(Str("hello"), Str("world")).toString())

实际上,java虽然是静态类型语言,但也实现了这种模式,如果不考虑int,long等基础类型,实际上所有的类型都是继承于Object,但是如果上面代码改成java代码,就无法运行,因为Object本身没有add之类的方法,所以就算传入的类型有这个方法,但是函数f本身会编译失败,之前说了,我的目标是设计一个类似python的动态类型语言,然后转成java代码,对象继承这个特性是连接这两种语言很重要的一环

个人经验,喜欢动态类型的人居多,这还是有道理的,因为用动态类型语言写代码,可以把更多精力放在“做什么”上,而不用考虑太多细节的“怎么做”,python只需要写一个[],然后往里面塞{},java可能就要写Vector<hashmap>这种折腾人的东西(java还没有运算符重载),于是再发展,就有了鸭子类型的概念 </hashmap

鸭子类型来自于这样一个说法,假如一个动物各方面都跟鸭子一样,那么它就是一只鸭子,或者说我们把它当鸭子对待,没有任何问题,哪怕它实际是一个钢铁做的机器。不关注是什么,只看重怎么用

python就是鸭子类型语言,例如这个代码:

def f(a):   
    a.g(1,2,3)

f并不关心传入的a究竟是什么,只要a有一个方法g并且g能接受三个整数参数,就可以了。python中只要一个对象实现了运算符()的重载,就能像函数或类一样调用,甚至只要你把一个对象“伪装”得跟一个类一样,就可以直接定义一个继承自它的类

其实静态类型语言也可以实现类似鸭子类型,不过这个后面再说了