Table特点
容器功能:与其他语言相似,lua也内置了容器功能,也就是table。而与其他语言不同的是,lua内置容器只有table。正因为如此,为了适配不同的应用需求,table的内部结构也比较考究,分为了数组和哈希表两个部分,根据不同需求来决定使用哪个部分。
面向对象功能:与其他语言不同的时,lua并没有把面向对象的功能以语法的形式包装给开发者。
但是我们可以用table 完成一个类似与面相对象的操作。
Table的数据结构
1.Table结构体
table是存放在GCObject里的。结构如下:
typedef struct Table {
CommonHeader;
lu_byte flags; /* 1<<p means tagmethod(p) is not present */
lu_byte lsizenode; /* 以2的lsizenode次方作为哈希表长度 */
struct Table *metatable /* 元表 */;
TValue *array; /* 数组 */
Node *node; /* 哈希表 */
Node *lastfree; /* 指向最后一个为闲置的链表空间 */
GCObject *gclist;
int sizearray; /* 数组的大小 */
} Table;
从table的结构可以看出,table在设计的时候以两种结构来存放数据。一般情况对于整数key,会用array来存放,而其它数据类型key会存放在哈希表上。并且用lsizenode作为链表的长度,sizearray作为数组长度。
2、Node结构体
typedef union TKey {
struct {
TValuefields;
struct Node *next; /* 指向下一个冲突node */
} nk;
TValue tvk;
} TKey;
typedef struct Node {
TValue i_val;
TKey i_key;
} Node;
Node结构很好理解,就是一个键值对的结构。主要是TKey结构,这里用了union,所以TKey的大小是nk的大小。并且实际上TValue与TValuefields是同一个结构,因此tvk与nk的TValuefields都是代表键值。而且这里有一个链表结构struct Node *next,用于指向下一个有冲突的node。
3.各成员的定义
CommonHeader:垃圾回收通用结构,详情参考本专栏数据结构篇。
flags:用于cache该表中实现了哪些元方法。
lsizenode:哈希表大小取log2(哈希表大小只会为2的次幂)
sizearray:数组大小(数组大小只会为2的次幂)
array:数组头指针
node:哈希表头指针
lastfree:哈希表可用尾指针,可用的节点只会小于该lastfree节点。
metatable:元表
gclist:GC的链表,用于垃圾回收。
Table的重要操作
1.创建table
table的创建通过lua_newtable函数实现。通过定位具体实现是在luaH_new这个函数进行table的创建。代码如下:
Table *luaH_new (lua_State *L, int narray, int nhash) {
Table *t = luaM_new(L, Table);/* new一个table对象 */
luaC_link(L, obj2gco(t), LUA_TTABLE);
t->metatable = NULL;
t->flags = cast_byte(~0);
/* temporary values (kept only if some malloc fails) */
t->array = NULL;
t->sizearray = 0;
t->lsizenode = 0;
t->node = cast(Node *, dummynode);
setarrayvector(L, t, narray);
setnodevector(L, t, nhash);
return t;
}
主要是对table进行初始化,其中setarrayvector是对数组大小进行设置,setnodevector是对hash表大小进行设置,具体代码如下:
/*
设置数组的容量
*/
static void setarrayvector (lua_State *L, Table *t, int size) {
int i;
//重新设置数组的大小
luaM_reallocvector(L, t->array, t->sizearray, size, TValue);
//循环把数组元素初始化为nil类型
for (i=t->sizearray; i<size; i++)
setnilvalue(&t->array[i]);
t->sizearray