当key作为table的key值时,会根据string的hash值去映射到数组上面。
string的hash值在创建的时候会对hash复制
//lstring.c:167
static TString *internshrstr (lua_State *L, const char *str, size_t l) {
TString *ts;
global_State *g = G(L);
unsigned int h = luaS_hash(str, l, g->seed);
...
ts = createstrobj(L, l, LUA_TSHRSTR, h);
...
return ts;
}
//lstring.c:133
static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {
TString *ts;
GCObject *o;
size_t totalsize; /* total size of TString object */
totalsize = sizelstring(l);
o = luaC_newobj(L, tag, totalsize);
ts = gco2ts(o);
ts->hash = h;
ts->extra = 0;
getstr(ts)[l] = '\0'; /* ending 0 */
return ts;
}
每次计算hash时都会用到hash种子也就是g->seed, hash种子在每次启动时都设置为当前时间
//lstate.c:295
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
...
g->seed = makeseed(L);
...
}
//lstate.c:81
static unsigned int makeseed (lua_State *L) {
...
unsigned int h = luai_makeseed();
...
}
//lstate.c:46
#define luai_makeseed() cast(unsigned int, time(NULL))
lua程序每次启动的g->seed都会不一样,导致相同的string,每次启动hash值都会不一样。 所以每当我们去遍历table的时候,重启之后就会发现顺序不一样。
这是lua5.3才加入的机制,在lua5.1中没有hash种子的概念。以下是lua5.1中的hsah值计算
//lua5.1 lstring.c:75
TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
GCObject *o;
unsigned int h = cast(unsigned int, l); /* seed */
size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */
size_t l1;
for (l1=l; l1>=step; l1-=step) /* compute hash */
h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1]));
for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)];
o != NULL;
o = o->gch.next) {
TString *ts = rawgco2ts(o);
if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) {
/* string may be dead */
if (isdead(G(L), o)) changewhite(o);
return ts;
}
}
return newlstr(L, str, l, h); /* not found */
}
若想要每次输出都一样的话 需要单独自己按key排序,然后再去遍历table
local v = {}
local sortTable = {}
for i,_ in pairs(v) do
if i ~= nil then
table.insert(sortTable, i)
end
end
-- 升序
table.sort(sortTable, function(a,b) return (a < b) end)
for _,sortKey in pairs(sortTable) do
print("key:"..sortKey.." value:"..v[sortKey])
end