Back to Top

lua小工具

备忘,备忘。

使用lua_ref来引用变量

int m_nluaFuncRef;

m_nluaFuncRef = lua_ref(L, LUA_REGISTRYINDEX); // 赋值,针对栈顶
lua_getref(L, m_nluaFuncRef); // 调用
lua_unref(L, m_nluaFuncRef); // 释放

遍历table

While traversing a table, do not call lua_tostring directly on a key, unless you know that the key is actually a string. Recall that lua_tostring changes the value at the given index; this confuses the next call to lua_next

lua_pushnil(L);
while (lua_next(L, nIndex))
{
    lua_pushvalue(L, -2); //lua_tostring key的时候会改变 key值,会导致遍历有问题,需要保护一下
    
    const char* pszKey = lua_tostring(L, -1);
    const char* pszValue = lua_tostring(L, -2);
    Params[pszKey] = pszValue;
    
    lua_pop(L, 2);
}
lua_remove(L, -1);

创建table

lua_newtable(L);
for (int nLine = 2; nLine <= nLineCount; nLine++)
{
    lua_pushinteger(L, nLine); // key
    lua_newtable(L);
    for (int nCol = 1; nCol <= nColumnCount; nCol++)
    {
        lua_pushstring(L, xx->pszKey);
        lua_pushstring(L, xx->pszValue);
        lua_settable(L, -3);
    }
    lua_settable(L, -3);
}

table操作

lua_PushObject(g_pUIMgr->m_pluaState, pNode);
lua_pushstring(g_pUIMgr->m_pluaState, CONTROL_KEY_NAME);
lua_gettable(g_pUIMgr->m_pluaState, -2);

nRetCode = lua_type(g_pUIMgr->m_pluaState, -1);
if (nRetCode != lua_TNIL)
{
    Log(eLogWarning, "[SetControlName] Redefinition of %s", pszMemberVariableName);
    goto Exit0;
}
lua_pop(g_pUIMgr->m_pluaState, 2);

lua_PushObject(g_pUIMgr->m_pluaState, pNode);
lua_pushstring(g_pUIMgr->m_pluaState, pszMemberVariableName);
lua_setfield(g_pUIMgr->m_pluaState, -2, CONTROL_KEY_NAME);
lua_pop(g_pUIMgr->m_pluaState, 1);

Import的lua版本

Import 是我们一直以来对lua文件间访问的封装,它有三个优点:

  1. 解决文件间的循环依赖
  2. 每个文件是一个独立的沙盒,不会污染全局变量
  3. 方便支持热更新

最早的版本用C语言实现的,后来我认为用lua实现更容易理解: (删除了对lua5.1的支持,如有需要可去github查看本文件历史。2016.04.15)

local function GetFileKey(name)
    return "FILE:" .. name;
end

function _G.Import(name)
    local key = GetFileKey(name); 
    if _G[key] then 
        return _G[key]; 
    end

    local tb = {}; 
    setmetatable(tb, {__index = _G});
    _G[key] = tb;

    local fn, msg = loadfile(name, "t", tb);
    if not fn then
        print(string.format("Import [%s] filed. %s", name, msg));
        return _G[key];
    end    
    fn(); 

    return _G[key];
end

function _G.ReImport(name) 
    local key = GetFileKey(name); 
    if not _G[key] then 
        return;
    end

    local fn, msg = loadfile(name, "t", _G[key]);
    if not fn then
        print(string.format("Re import [%s] filed. %s", name, msg));
        return;
    end    
    fn(); 
end

setmetatable

5.1的时候metatable只支持userdata,5.2支持table和userdata了

local cmd = setmetatable({}, { __gc = function() print("cmd clear") end })
print "set"
cmd = nil;
collectgarbage();
print "unset"

在5.1下不输出”cmd clear”,5.2下输出。

luajit相关

luajit与lua相比: 优点:

  1. 可以提高性能
  2. 可以使用ffi加快开发速度

缺点:

  1. luajit 在 64 位平台下,只能使用 1G 内存。即使在同一进程内开辟多个 lua state 也不例外。查看代码可以知道,luajit 为了结合更高效的 gc ,使用了自己的内存管理器。这需要用一个 32 位的伪指针工作。为了适应 64 位平台,它强制让分配器分配出来的内存的高位都必须是 0 。所以,多个 lua state 也需要满足这个条件,而不可能突破 4G 的限制。
  2. luajit 居然使用了 NaN Trick ,这导致 lightuserdata 仅有 48 位有效值(可见 luajit 的源代码 lj_obj.h)。

{…} 不同

function test(...)
	local tb  = {...}
	print(#tb, unpack(tb))
end
test("as", nil, 1,2)

lua 输出

4	as	nil	1	2

luajit输出

2	as