全局变量声明的规范化(转)

  Lua将环境本身存储在一个全局变量_G中,(_G._G等于_G)。为了对全局命名空间更好的管理,最好是显示的声明每一个变量,可以通过使用metamethod来改变_G的行为来进行规范:

复制代码
复制代码
-- 声明新的变量,使用rawset绕过metamethod的限制
-- 保证声明的变量不为nil,如果声明一个nil变量,等于该变量还是不存在,访问该变量的时候还是会触发__index
declare = function(name, initval)
    rawset(_G, name, initval or false)
end

--改变全局变量的访问行为
setmetatable(_G, 
    {__newindex = function (_, n)
    error("attempt to write to undeclared variable " ..n, 2)
    end,
    
    __index = function(_, n)
    error("attempt to read undeclared variable "..n, 2)
    end,}
)

declare("a")
a = 1
print(a)    -- 1
a = nil
print(a)    -- error 触发__index,因为该变量已经释放了
复制代码
复制代码

  上述代码中,每一个变量都需要显示declare,并且不能声明nil变量。

  下面这种方法可以声明nil变量,但需要用一个表来显示的记录每一个声明过的变量:

复制代码
复制代码
local declareNames = {}
function declare(name, initval)
    rawset(_G, name, initval)
    declareNames[name] = true
end

setmetatable(_G, 
    {__newindex = function (t, n, v)
        if not declareNames[n] then
            error("attempt to write to undeclared var. " ..n, 2)
        else
            rawset(t, n, v)
        end
    end,

    __index = function (_, n)
        if not declareNames[n] then
            error("attempt to read undeclared var. "..n, 2)
        else
                return nil
        end
    end}
)

declare("a")
a = 1
print(a)        -- 1
a = nil
print(a)        -- nil 还是可以访问
复制代码
复制代码

  个人偏向于第一种方法,因为第二种方法中,当一个变量被置为nil以后,实际上该变量已经被释放了,所以将变量的置空操作封装在一个undeclear函数中。对第二种方法的改进:

复制代码
复制代码
local declareNames = {}
function declare(name, initval)
    rawset(_G, name, initval)
    declareNames[name] = true
end

function undeclare(name)
    declareNames[name] = nil
    rawset(_G, name, nil)
end

setmetatable(_G, 
    {__newindex = function (t, n, v)
        if not declareNames[n] then
            error("attempt to write to undeclared var. " ..n, 2)
        else
            rawset(t, n, v)
        end
    end,

    __index = function (_, n)
        if not declareNames[n] then
            error("attempt to read undeclared var. "..n, 2)
        else
                return nil
        end
    end}
)

declare("a")
a = 1
print(a)        -- 1
undeclare("a")
print(a)        -- error 变量已经不存在了,会触发__index
复制代码
复制代码

  两种方法的代价都很小,可以忽略不计,但是给整个编程环境带来的好处是不言而喻的。

http://www.cnblogs.com/sifenkesi/p/3838311.html

posted @   沧海一滴  阅读(652)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
历史上的今天:
2015-03-04 Eclipse下快速打开本地文件插件EasyExplorer(转)
2015-03-04 winXP JDK由1.8改为1.6
点击右上角即可分享
微信分享提示