Lua向表内新增元素(N)主要走的是luaH_newkey函数。其过程大体如下:
根据给定的key计算出应该存放的位置P

  • 如果P处没有元素,直接存放就好
  • 如果P处已经有元素,这时存在两种情况:
  • 在P处发生了碰撞,需要在物理上将N存放到下一个空位,并从逻辑上将N连接到P的链表中
  • 在别处放生碰撞的元素(O)被放到P处,需要将O移到下一个空位,将N存放到P处

lua table 嵌套table lua的table添加元素_lua table 嵌套table


可以看到,无论何处发生的碰撞导致P处被占据,此时都要找到一个新的空位置F来存放新元素N,而当空间已满的时候,无法找到新的F,此时就会触发重散列的过程,调用rehash方法。

lua table 嵌套table lua的table添加元素_Lua_02


我们知道,Lua的表包括了数组和散列表两部分,这两部分的大小如何分配、整数键的元素是放到数组中还是放到散列表中,都是由Lua自行决定的。这个自行决定的完整过程,就是rehash方法的内容。

Lua分配这两部分空间的原则也很简单,即优先计算数组部分,剩下的部分全放到散列表里。而如何决定数组部分的大小,Lua的作者们在《The Implementation of Lua 5.0》中已经说得很明白了:

  • 数组的空间至少有一半以上被利用(保证空间的利用率)
  • 数组的后半部分内至少有一个元素(避免只要一半空间就能装满却多浪费了一倍空间的情况)

为此,我们在重散列的过程中需要知道:

  • 一共有多少个有效的整数key(value不为空)—— 变量na
  • 这些整数key的分布情况 —— nums数组
  • 所有的key的数量(用于计算散列表部分的容量)—— 变量totaluse

所以,rehash的逻辑也很清晰:

  • 通过numusearray统计数组部分内包含的整数key数量和分布情况
  • 通过numusehash统计散列表部分内包含的整数key数量和分布情况,并得到总共key的数量
  • 通过computesizes计算应该分配给数组部分的空间大小
  • 通过luaH_resize按照之前计算的结果重新分配空间

lua table 嵌套table lua的table添加元素_散列表_03

lua table 嵌套table lua的table添加元素_lua_04


lua table 嵌套table lua的table添加元素_lua table 嵌套table_05


lua table 嵌套table lua的table添加元素_数组_06