• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

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

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
  • 元表概念:

    • 引言: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》元表与元方法整张的实例

    --[[
    Set = {}
    mt = {} --元表
    
    function Set.new(l)
    	local set = {}
    	setmetatable(set, mt)
    	for _, v in ipairs(l) do
    		set[v] = true
    	end
    	return set
    end
    
    
    --================================================
    function Set.tostring(set)
    	local l = {}
    	for e in 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 k in pairs(a) do res[k] = true end
    	for k in 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 k in 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 k in 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"

  •            

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
在OpenResty中使用lua-zlib的方法在OpenResty中使用lua-zlib的方法发布时间:2022-07-22
下一篇:
Lua中的随机种子发布时间:2022-07-22
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap