1. 程式人生 > >探訪lua5.2新特性及package機制模擬

探訪lua5.2新特性及package機制模擬

專案客戶端指令碼全面升級lua5.2 這是自06年後最大的一次主幹更新, 帶來的機制, 函式變化也是非常不錯的

1. 去掉了全域性性質的setfenv/getfenv系列函式, 語言層面提供_ENV語法糖, 這東西跟:操作符一樣, 只存在於編譯期.

官方建議自己實現module/require/package機制, 畢竟原生這套機制實現太弱智了..

2. 提供了無符號訪問函式

3. 更多的lua api變化. 如果想相容lua5.1的寫法, 可以參考luabridge內LuaHelpers.h的實現

以下是本人使用lua5.2實現的一套package機制, 供大家參考

package = {}
-- 讀取標記
package.loaded = {}
-- 搜尋路徑陣列
package.path = {}
package.access =
{
    ["string"] = string,
    ["print"] = print,
    ["table"] = table,
    ["assert"] = assert,
    ["error"] = error,
    ["pairs"] = pairs,
    ["ipairs"] = ipairs,
    ["tonumber"] = tonumber,
    ["tostring"] = tostring,
    ["type"] = type,
    ["math"
] = math,
}
local function getreadablepath( name, pathlist )
    for _, path in ipairs(pathlist) do
        local fullpath = path .. "/" .. name .. ".lua"
        local f = io.open( fullpath )
        if f then
            f:close()
            return fullpath
        end
    end
    return nil
end
function package.import( name )
    -- 已經讀取的直接返回
    local existedenv = package.loaded[name]
    if existedenv then
        return existedenv
    end
    local access = package.access
    -- 設定訪問控制權限
    local meta = 
    {
        __index = function( tab, key )
            -- 優先取包的空間
            local v = rawget( tab, key )
            if v then
                return v
            end
            -- 找不到時,從可訪問的許可權表中查詢
            return access[key]             
        end,
    }
    -- 初始化一個包的全域性環境, 並設定訪問方法
    local env = setmetatable( {} , meta )
    --
    local readablepath = getreadablepath( name, package.path )
    if not readablepath then
        error(string.format("package '%s' not found \n%s", name, table.concat( package.path, "\n" ) ) )
    end
    local func = loadfile( readablepath, "bt",  env )
    if type(func) ~= "function" then
        return nil
    end
    -- 設定標記
    package.loaded[name] = env
    -- 執行全域性空間
    func( )
    return env
end
package.path = {"E:/Download/t"}
local m = package.import "m"
m.foo()
以下是m模組(m.lua)的內容
function foo( )
    print("轉載註明: 戰魂小築 http://www.cppblog.com/sunicdavy", io )    
end

測試結果中, io打印出nil, 顯示許可權已經被控制住

本package設計比原生package更靈活, 更強大