博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
lua 元表
阅读量:5102 次
发布时间:2019-06-13

本文共 4055 字,大约阅读时间需要 13 分钟。

在Lua table中,我们可以对table中的key,value进行操作处理,但无法对两个table进行加减操作,比如:

local tabA = {
1,2,3}local tabB = {
4,5}local tabC = tabA + tabB-- Error: attempt to perform arithmetic on local 'tabA' (a table value)

因此,Lua提供了元表(metatables),允许我们改变table的行为。假如两个table进行相加操作时,lua会检查两个表是否存在Metatable,并且检查Metatable是否有__add域,即元表方法,如果存在,则通过_add执行相加结果。比如:

local meta = {}meta.__add = function(t1,t2)    local tmp = {}    for _, v in pairs(t1) do        table.insert(tmp,v)    end    for _, v in pairs(t2) do        table.insert(tmp,v)    end    return tmpendlocal tab1 = {
1,2,3}local tab2 = {
4,5}-- 设定元表setmetatable(tab1,meta)setmetatable(tab2,meta)-- 执行相加操作local tab3 = tab1 + tab2print(table.concat(tab3,",")) -- 1,2,3,4,5

lua默认情况下是不存在元表的,我们可以通过getmetatable(table),setmetatable(table,metatable) 来获取或者设定元表的组成,比如:

-- 默认不存在元表,查询方法: getmetatablelocal tabA = {}print(getmetatable(tabA))-- 设定元表,设置方法: setmetatable()local tabB = {}local meta = {}      -- 任何表都可以成为元表setmetatable(tabB, meta)assert(getmetatable(tabB) == meta)

一组相关的表,可以共享一个元表,比如:

-- 元表相关local meta = {}meta.__add = function(t1,t2)    local tmp = {}    for _, v in pairs(t1) do        table.insert(tmp,v)    end    for _, v in pairs(t2) do        table.insert(tmp,v)    end    return tmpendlocal tab1 = {
1,2,3}local tab2 = {
4,5}-- 设定元表,也可以设定任意一个--[[原因:如果第一个参数存在__add域的元表,lua将使用第一个作为元表方法。 同样,如果第二个参数存在__add域的元表,lua将使用第二个作为元表方法 这是lua选择元表方法的原则]]setmetatable(tab1,meta)setmetatable(tab2,meta)-- 执行相加操作local tab3 = tab1 + tab2print(table.concat(tab3,",")) -- 1,2,3,4,5

在lua中,元表都有着对应的域名或者元方法(metaMethod)与运算符相对应,以及其他元方法,如下(注意: __是两个下划线):

算术运算符 域名
加 + __add
减 - __sub
乘 * __mul
除 / __div
模 % __mod
取反 __unm
连接符 .. __concat
__pow
等于 __eq
小于 __lt
小于等于 __le
不等于 没有域名,会由 a ~= b 转换为 not(a==b)
大于 没有域名,会由 a > b 转换为 b < a
大于等于 没有域名, 会由 a >= b 转换为 b <= a
函数调用
__call
转为字符串 __tostring
调用索引 __index
给索引赋值 __newindex

可参考C库中的ltm.c文件,如下:

void luaT_init (lua_State *L) {  static const char *const luaT_eventname[] = {  /* ORDER TM */    "__index", "__newindex",    "__gc", "__mode", "__len", "__eq",    "__add", "__sub", "__mul", "__mod", "__pow",    "__div", "__idiv",    "__band", "__bor", "__bxor", "__shl", "__shr",    "__unm", "__bnot", "__lt", "__le",    "__concat", "__call"  };  int i;  for (i=0; i
tmname[i] = luaS_new(L, luaT_eventname[i]); luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */ }}

接下来,我们来模拟下几个元表方法:

__index:

用于对表的访问,当调用table的一个不存在的key时,如果这个key没有,lua会查找元表的__index。__index可以是table也可以是方法

作为table:查找__index元方法表,若有,则返回该索引对应的值,否则返回nil

local meta = {}meta.__index = {key = "meta"}local tab = {one = 1,two = 2}print(tab.key)            -- nilsetmetatable(tab, meta)print(tab.key)            -- meta

代码也可编写为:

local tab = setmetatable({one = 1,two = 2},{__index = {key = "meta"}})print(tab.key)             -- meta

作为方法:将表和索引作为参数传入__index,return返回值

local meta = {}-- 参数分别为:表自己,索引meta.__index = function(tab,key)    if key == "key2" then        return "meta value2"    end    return nilendlocal tab = {key1 = "value1"}print(tab.key1, tab.key2)     -- value1    nilsetmetatable(tab, meta)print(tab.key1, tab.key2)     -- value1    meta value2

注意,查找key时,如果表中存在,则使用表自己的,如果不存在,则查找元表中的。比如:

local meta = {}-- 参数分别为:表自己,索引meta.__index = function(tab,key)    if key == "key2" then        return "meta value2"    end    return nilendlocal tab = {key1 = "value1",key2 = "value2"}print(tab.key1, tab.key2)     -- value1    value2setmetatable(tab, meta)print(tab.key1, tab.key2)     -- value1    value2

__newindex

主要用于对表数据的更新,当为table中一个不存在的索引赋值时,会去调用元表中的__newindex元方法,如果存在则调用该表而不进行赋值操作

local metaTab = {}              -- 元方法中的表local tab = {key = "key1"}         -- 自己的表setmetatable(tab,{__newindex = metaTab})print(tab.key)         -- key1-- 给自己的表中不存在的索引赋值tab.newkey = "newkey"-- 自己的还是为空,实质上其赋值操作是调用了__newindex的表,而非自己print(tab.newkey, metaTab.newkey)         -- nil  newkey1-- 给自己表中原有索引重新赋值tab.key = "new key1"-- 已存在的索引赋值,不会再调用__indexprint(tab.key, metaTab.key)             -- new key1      nil

后续的再做补充...

 参考:

 

转载于:https://www.cnblogs.com/SkyflyBird/p/10075867.html

你可能感兴趣的文章
小别离
查看>>
微信小程序-发起 HTTPS 请求
查看>>
WPF动画设置1(转)
查看>>
基于node/mongo的App Docker化测试环境搭建
查看>>
java web 中base64传输的坑
查看>>
java 中的线程(一)
查看>>
秒杀9种排序算法(JavaScript版)
查看>>
Activiti入门 -- 环境搭建和核心API简介
查看>>
struts.convention.classes.reload配置为true,tomcat启动报错
查看>>
MySQL的并行复制多线程复制MTS(Multi-Threaded Slaves)
查看>>
好玩的-记最近玩的几个经典ipad ios游戏
查看>>
MySQL更改默认的数据文档存储目录
查看>>
PyQt5--EventSender
查看>>
Sql Server 中由数字转换为指定长度的字符串
查看>>
Java 多态 虚方法
查看>>
Unity之fragment shader中如何获得视口空间中的坐标
查看>>
万能的SQLHelper帮助类
查看>>
uboot分析:uboot的启动过程分析
查看>>
tmux的简单快捷键
查看>>
[Swift]LeetCode922.按奇偶排序数组 II | Sort Array By Parity II
查看>>