第十三章 元表与元方法

元表

  • 基础知识

lua中的每个值都有一个元表。table和userdata都可以有各自独立的元表,而其它类型的值则共享其类型所属的单一元表。Lua在创建新的table时不会创建元表。任何table都可以作为任何值的元表,而一组相关的table也可以共享一个通用的元表,此元表描述了他们共同的行为。一个table甚至可以作为他自己的元表,用于描述其特有的行为。总之任何搭配形式都是合法的。

  1. 普通元表.
  2. 弱引用table(Weak Table)
  3. 备忘录元表(这项技术也需要用到弱引用table),它能使具有相同默认值的table复用同一个元表。
local t = {}
print(getmetatable(t))        -->nil
local t1 = {}
setmetatable(t, t1)
print(getmetatable(t) == t1)        -->true

在lua代码中,只能设置table的元表。若要设置其它类型的值的元表,则必须通过C代码来完成。标准的字符串程序库为所有的字符串都设置了一个元表,而其他类型在默认情况中都没有元表。

print(getmetatable("hi"))        -->table: 000000001ED78460
print(getmetatable("hi") == getmetatable("h"))        -->true
print(getmetatable(10))            -->nil
  1. setmetatable(t, mt) 设置一个table t的元表mt
  2. getmetatable(t) 获取table t的元表

元方法

  1. 算数类的元方法
  2. 关系类的元方法
  3. 库定义的元方法
  4. table访问的元方法(类似于get和set)

跟踪table的访问(使用代理)

这段主要讲述为了捕捉到所有对table的访问所做的常规应用方法。解释如下:

__index和__newindex都是在table中没有所需访问的index时才发挥作用的。因此,只有将一个table保持为空,才有可能捕捉到所有对它的访问。为了监视一个table的所有访问,就应该为真正的table创建一个代理。这个代理就是一个空的table。其中__index和__newindex元方法可以用于跟踪所有的访问,并将访问重定向到原来的table上。那么可以这么做:

--[[
此处代码按照书上讲解copy,不过为了避免看书自己看错,把变量名作了区分,避免新人无法理解看错的问题。
--]]
local t = {}        --原来的table(在其它地方创建的)

--保持对原table的一个私有访问
local _t = t
--创建代理
local tproxy = {}
--创建元表
local mt = {
    __index = function(t, k)
        print("access to element "..tostring(k))
        return _t[k]            --访问原来的table
    end,
    __newindex = function(t, k, v)
        print("*update of element "..tostring(k).."to "..tostring(v))
        _t[k] = v                --更新原来的table
    end
}
setmetatable(tproxy, mt)
tproxy[2] = "hello"        
--> *update of element 2to hello
print(tproxy[2])
-->access to element 2
-->hello

只读的table(通过代理的概念实现)

function readOnly(t)
    local proxy = {}
    local mt = {    --创建元表
        __index = t,
        __newindex = function(t, k, v)
            error("attempt to update a read-only table", 2)
        end
    }
    setmetatable(proxy, mt)
    return proxy
end

local days = readOnly{"Sunday", "Monday", "tuesday", "Wednesday", "Thursday",
"Friday", "Saturday"}

print(days[1])   -->Sunday
days[2] = "Noday" --直接报错

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值