利用__index和__newindex实现默认值表、监控表、只读表(转)

__index和__newindex实际上相当于是在读写表的时候分别加了一道过滤的逻辑,让读写表的操作可以被监控或说回调,利用这个特性可以实现一些带有特殊功能的表。

  带有默认值的表:

复制代码
复制代码
setdefault = function(t, v)
    setmetatable(t, {__index = function () return v end})
end

s = {1, 2, 3}
setdefault(s, 0)        -- 默认值设为0
print(s.x)
复制代码
复制代码

  一般访问不存在的域会返回nil,但经过上面代码处理后,访问不存在的域会返回一个默认值。为了实现公用metatable,可以将代码封装如下:

key = {}
local mt = {__index = function (t) return t[key] end}
function setdefault(t, d)
    t[key] = d
    setmetatable(t, mt)
end

  监控表(代理表):

复制代码
复制代码
t = {} --需要监控的表
local _t = t
t = {} --代理表需要为空,因为只有当读写不存在的域时,才会触发__index和__newindex

local mt = {
    __index = function (t, k)
    print("*access to element"..tostring(k))
    return _t[k]
    end,
    
    __newindex = function(t, k, v)
    print("*update of element " .. tostring(k) .. " to " .. tostring(v))    
    _t[k] = v
    end
}

setmetatable(t, mt)

t[2] = 'hello'
print(t[2])
复制代码
复制代码

  对上述代码进行一些适当的封装,将原始表作为代理表的一个特殊的域对应的值:

复制代码
复制代码
local index = {}

local mt = {
    __index = function (t, k)
        print("*access to element " .. tostring(k))
        return t[index][k]
    end,

    __newindex = function (t, k , v)
        print("*update of element " .. tostring(k) .. " to " .. tostring(v))
        t[index][k] = v
    end
}

track = function (t)
    local proxy = {}
    proxy[index] = t
    setmetatable(proxy, mt)
    return proxy
end

t = track(t)
复制代码
复制代码

  只读表:

复制代码
复制代码
function readOnly(t)
    local proxy = {}
    local mt = {
        __index = t,
        __newindex = function (t, k, v)
            error("attemp to uopdaate a read-only table", 2)
        end
    }

    setmetatable(proxy, mt)
    return proxy
end

days = readOnly{"Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday"}
print(days[1])
days[2] = "Noday"
复制代码
复制代码

  上述利用__index和__newindex特性来实现的一些具有特殊表的方法都比较简单易懂,而且很好用。

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

posted @   沧海一滴  阅读(298)  评论(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
点击右上角即可分享
微信分享提示