Lua:元表(metatable)与元方法(meatmethod)

  • 元表概念:

    • 引言:Lua中的每个值都有一套预定义的操作集合,如数字相加等。但无法将两个table相加,此时可通过元表修改一个值的行为,使其在面对一个非预定义的操作时执行一个指定操作。

    • 访问机制:一般的元方法都只针对Lua的核心,也就是一个虚拟机。它会检测一个操作中的值是否有元表,这些元表是否定义了关于次操作的元方法。例如两个table相加,先检查两者之一是否有元表,之后检查是否有一个叫“__add”的字段,若找到,则调用对应的值。“__add”等即时字段,其对应的值(往往是一个函数或是table)就是“元方法”。

  • 元表实例

    • setmetatable(只能用于table)和getmetatable(用于任何对象)

      • 语法:setmetatable (table, metatable),对指定table设置metatable      【如果元表(metatable)中存在__metatable键值,setmetatable会失败】

      • 语法:tmeta = getmetatable (tab),返回对象的元表(metatable)             【如果元表(metatable)中存在__metatable键值,当返回__metatable的值】

      • 代码:

        print(getmetatable("lua")) -->table: 002F19B8
        print(getmetatable(10))    -->nil
         
         
        --使用__metatable可以保护元表,禁止用户访问元表中的成员或者修改元表。
        tA = {}
        mt = {}
        getmetatable(tA, mt)
        mt.__metatable = "lock"
        setmetatable(tA, mt)
        print(getmetatable(tA))  -->lock


    • 算术类元方法:     字段:__add  __mul  __ sub  __div  __unm  __mod  __pow  (__concat)
      • 代码:(两个table相加)
        tA = {1, 3}
        tB = {5, 7}
         
        --tSum = tA + tB
        mt = {}
         
        mt.__add = function(t1, t2)
            for _, item in ipairs(t2)do
                table.insert(t1, item)
            end
        return t1
        end
         
        setmetatable(tA, mt)
         
        tSum = tA + tB
         
        for k, v in pairs(tSum)do
            print(v)
        end


    • 关系类元方法: 字段:__eq __lt(<) __le(<=),其他Lua自动转换 a~=b --> not(a == b) a > b --> b < a a >= b --> b <= a 【注意NaN的情况】
      • 代码:
        --比较集合大小 <
        mt = {}
        function mt.__lt(tA, tB)
            return #tA < #tB
        end
         
        tA, tB = {3}, {1, 2}
         
        setmetatable(tA, mt)
        setmetatable(tB, mt)
         
        print(tA < tB)
    • table访问的元方法: 字段: __index __newindex
      • __index: 
            查询:访问表中不存的字段 
            rawget(t, i)

      • __newindex: 
            更新:向表中不存在索引赋值 
            rawswt(t, k, v)

  • 贯穿《Programming in Lua》元表与元方法整张的实例

    <span style="font-family: 黑体;">--[[
    Set = {}
    mt = {} --元表
     
    function Set.new(l)
        localset = {}
        setmetatable(set, mt)
        for _, v in ipairs(l)do
            set[v] = true
        end
        return set
    end
     
     
    --================================================
    function Set.tostring(set)
        local l = {}
        for ein pairs(set)do
            l[#l + 1] = e
        end
        return "{" .. table.concat(l, ",") .. "}"
    end
     
     
    function Set.print(s)
        print(Set.tostring(s))
    end
     
     
    --1 加(__add), 并集===============================
    function Set.union(a, b)
    --[[   if getmetatable(a) ~= mt or getmetatable(b) ~= mt then
            error("attemp to 'add' a set with a non-set value", 2)   --error第二个参数的含义P116
        end]]
        local res = Set.new{}
        for kin pairs(a)do res[k] = true end
        for kin pairs(b)do res[k] = true end
        return res
    end
     
    s1 = Set.new{10, 20, 30, 50}
    s2 = Set.new{30, 1}
    --print(getmetatable(s1))
    --print(getmetatable(s2))
     
    mt.__add = Set.union
     
    s3 = s1 + s2
    --Set.print(s3)
     
    --[[元表混用
    s = Set.new{1, 2, 3}
    s = s + 8
    Set.print(s + 8)
    ]]
     
    --2 乘(__mul), 交集==============================
    function Set.intersection(a, b)
        local res = Set.new{}
        for kin pairs(a)do
            res[k] = b[k]
        end
        return res
    end
     
    mt.__mul = Set.intersection
     
    --Set.print(s2 * s1)
     
     
     
    --3 关系类===================================NaN的概念====
    mt.__le = function(a, b)
        for kin pairs(a)do
            if not b[k] then return false end
        end
    return true
    end
     
    mt.__lt = function(a, b)
        return a <= b and not (b <= a)
    end
     
    mt.__eq = function(a, b)           --竟然能这么用!?----
        return a <= b and b <= a
    end
     
    g1 = Set.new{2, 4, 3}
    g2 = Set.new{4, 10, 2}
    print(g1 <= g2)
    print(g1 < g2)
    print(g1 >= g2)
    print(g1 > g2)
    print(g1 == g1 * g2)
     
    --]]
     
    --============================================
    --4 table访问的元方法=========================
    --[[
    --__index有关继承的典型示例
    Window = {}
    Window.prototype = {x = 0, y = 0, width = 100, height}
    Window.mt = {}
     
    function Window.new(o)
        setmetatable(o, Window.mt)
        return o
    end
     
    Window.mt.__index = function (table, key)
        return Window.prototype[key]
    end
     
    w = Window.new{x = 10, y = 20}
    print(w.width)
     
    --__index修改table默认值
    function setDefault (t, d)
        local mt = {__index = function () return d end}
        setmetatable(t, mt)
    end
     
    tab = {x = 10, y = 20}
    print(tab.x, tab.z)
    setDefault(tab, 0)
    print(tab.x, tab.z)
     
    --]]
     
    --13.4.5 只读的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
     
    days = readOnly{"Sunday","Monday","Tuesday","W","T","F","S"}
    print(days[1])
    days[2] = "Noday"</span>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值