ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Lua中的metatable

2021-03-10 20:35:19  阅读:178  来源: 互联网

标签:__ mt local Lua print setmetatable metatable


Lua的metatable定义了大量的元方法,有些可以当作操作符重载来使用。例如,__add方法定义了对一个table使用+操作符时所发生的行为,但是,+操作符是二元操作符,假如只有一个操作数定义了__add方法,这时候运算还会成立吗?我们可以尝试一下:

local u = {x = 1, y = 1}
local v = {x = 2, y = 2}
local mt = { __add = function(l, r) return {x = l.x + r.x, y = l.y + r.y} end }
setmetatable(u, mt)
local w = u + v
print(w.x, w.y)

运行发现并不会报错,而且得到了我们想要的结果。对于这类二元操作符,Lua只要检测到两个操作数中有一个定义了对应的元方法,就会去执行它,并不强制要求另外一个也要定义。当然,如果两个操作数都没有,那就会报错了:

local u = {x = 1, y = 1}
local v = {x = 2, y = 2}
-- local mt = { __add = function(l, r) return {x = l.x + r.x, y = l.y + r.y} end }
-- setmetatable(u, mt)
local w = u + v
print(w.x, w.y)

另外,对于关系操作符(==~=>=<=><)来说,Lua提供了3个元方法来重载它们:__eq__le__lt。它们的对应关系如下:

操作符 元方法
a == b __eq(a, b)
a ~= b not __eq(a, b)
a >= b __le(b, a)
a <= b __le(a, b)
a > b __lt(b, a)
a < b __lt(a, b)

值得一提的是,在Lua中,a >= b并不等价于not a <= b。这是因为,存在一些无法比较大小的可能性,例如一些非法值(NaN),在比较运算中都应当返回false。如果使用not,那就会出现返回true的情况。

Lua的print方法会调用__tostring元方法来打印数据,例如:

local u = {x = 1, y = 1}
local mt = { __tostring = function(obj) return "x " .. obj.x .. " y " .. obj.y end }
setmetatable(u, mt)
print(u)

Lua的__index元方法既可以是一个函数,又可以是一个table,如果是table,就相当于对该table执行一次取数据操作,相当于有个默认值:

local base = {x = 0, y = 0}
local u = {}
local mt = { __index = base }
setmetatable(u, mt)
print(u.x, u.y)

当table t不存在key k的时候,t[k]就会触发t的__index方法,有时候我们并不想触发,就可以使用rawget方法,使用这个效率并不一定更高,因为涉及到了函数的调用。

Lua还提供了__pairs元方法来重载默认的pairs行为。例如,我们可能想在使用pairs的时候一并打印遍历的key和value:

local u = {x = 1, y = 2}
local mt =
{
    __pairs = function(a)
        local iter = function(s, t)
            local nk, nv = next(s, t)
            if nk then
                print("next ", nk, nv)
            end
            return nk, nv
        end
        return iter, a, nil
    end
}
setmetatable(u, mt)
for k, v in pairs(u) do
end

__pairs的参数和返回值和pairs一样,参数为迭代的table,返回值为迭代器函数,不变量,和状态变量。

为了避免metatable被外部修改,Lua提供了__metatable元方法,当该方法有值时,调用getmetatable会返回该值,再次setmetatable会报错:

local u = {x = 1, y = 2}
local mt =
{
    __metatable = "read only metatable"
}
setmetatable(u, mt)
print(getmetatable(u, mt))
setmetatable(u, {})

如果你觉得我的文章有帮助,欢迎关注我的微信公众号(大龄社畜的游戏开发之路-

标签:__,mt,local,Lua,print,setmetatable,metatable
来源: https://www.cnblogs.com/back-to-the-past/p/14514016.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有