Lua
是动态类型语言,变量不要类型定义,只需要为变量赋值。 值可以存储在变量中,作为参数传递或结果返回。
八种基本数据类型
Lua
的类型系统是相对稳定的。很长时间里,Lua
只有6个基本类型:nil
,number
,string
,table
,function
和userdata
(实际上,直到Lua 3.0
为止,之前的C
函数和Lua
函数有不同的内部类型,但是这个差异对于调用者是透明的)。唯一真正的改变来自于Lua 5.0
,这个版本引入了两个新类型:thread
和boolean
。
1 |
变量第一次赋值之前,值为nil
。
第一类值
lua
中所有值都是第一类值,他们可以存在变量中(无论全局变量还是局部变量)或table
中,可以作为函数参数,可以作为返回值。
Lua通用数据结构的实现
C语言中实现通用数据结构的一般做法
如果要使用一个通用的数据结构来表示不同的数据类型,一般的做法是:
- 需要一个字段来存储数据的类型
- 需要存储不同的数据类型的数据
这里有这两种实现方法
- 定义一个公共的数据结构作为基础类型,里面存储的都是表达这个数据的基础信息,其他具体的类型是从这里派生出来的 。 这就是一般的面向对象的思路。
- 使用联舍
( union )
来将所有数据包进来
上面两种做法各有利弊 。 在Lua代码中,一般采用两种做法相结合的方式。
具体实现
Lua
需要进行GC
操作的数据类型都会有一个CommonHeader
宏定义的成员,并且这个成员在结构体定义的最开始部分。
1 |
任何需要进行垃圾回收处理的Lua
数据类型,必然以CommonHeader
作为该结构体定义的最开始部分。如果熟悉C++类的实现原理,可以将CommoHeader
这个成员理解为一个基类的所有成员,而其他需要回收处理的数据类型均从这个基类继承下来,所以它们的结构体定义的开始部分就是这个成员。
还有一个名为GCheader
的结构体,其中的成员只有Common Header
:
1 | typedef struct GCheader { |
于是,在Lua
中就使用了GCObject
联合体将所有需要进行垃圾回收的数据类型囊括了进来:
1 | union GCObject { |
GCObject
这个联合体,将所有需要进行垃圾回收的数据类型全部囊括其中,这样定位和查找不同类型的数据时就方便多了。
还有几种数据类型是不需要进行垃圾回收的,Lua
中将GCObject
和它们一起放在了联合体Value
中:
1 | typedef union { |
到了这一步 ,差不多可以表示Lua
中所有的数据类型了。但是还欠缺一点东西,那就是这些数据到底是什么类型的。于是Lua
代码中又有了TValue
,它用于将Value
和类型结合在一起。
1 |
|
前面提到过, Lua
同时采用了两种方式来做到数据统一。根据前面的分析,这表现在以下两个方面。
- 具体类型中有
CommonHeader
用来存放所有数据类型都通用的字段 TValue
作为统一表示所有数据的数据结构,内部使用了联合体Value
将所有数据都包起来
在具体的代码中,TValue
用于统一地表示数据,而一旦知道了具体的类型,就需要使用具体的类型了。因此,代码中有不少涉及TValue
与具体类型之间转换的代码,其主要逻辑都是将TValue
中的tt
、value
与具体类型的数据进行转换。
如将lua Number
转换为TValue
的宏setnvalue
:
1 |
|
从lua-5.1.1中分离出来的动态类型实现代码
reference
《Lua设计与实现》
Debemos esforzarnos por vencer todas las dificultades y procurar el mejor resultado posibl.