调用__index方法--rawget是为了绕过__index而出现的
讲到元表,先看一段table的合并行动.
t1 = {1,2} t2 = {3,4} t3 = t1 + t2 attempt to perform arithmetic on a table value (global 't1')措施会报错,因为不知道如何对两个table执行+运算,这个时候就需要通过元表来界说,有点类似c中的运算符加载。我们看一下如何通过元表实现合并操纵。
local mt = {} --界说mt.__add元要领(其实就是元表中一个特殊的索引值)为将两个表的元素合并后返回一个新表 mt.__add = function(t1,t2) local temp = {} for _,v in pairs(t1) do table.insert(temp,v) end for _,v in pairs(t2) do table.insert(temp,v) end return temp end local t1 = {1,2,3} local t2 = {2} --设置t1的元表为mt setmetatable(t1,mt) local t3 = t1 + t2 --输出t3 local st = "{" for _,v in pairs(t3) do st = st..v..", " end st = st.."}" print(st) {1, 2, 3, 2, }可以看到, 措施在执行的时候,挪用了mt._add元要领计算。
具体的过程是:
1.检察t1是否有元表,若有,则检察t1的元表是否有__add元要领,若有则挪用。
2.检察t2是否有元表,若有,,则检察t2的元表是否有__add元要领,若有则挪用。
3.若都没有则会报错。
**所以说,我们通过界说了t1元表的__add元要领,到达了让两个表通过+号来相加的效果**
Lua 查找一个表元素时的法则,其实就是如下 3 个法式:
1.在表中查找,如果找到,返回该元素,找不到则继续
2.判断该表是否有元表,如果没有元表,返回 nil,有元表则继续。
3.判断元表有没有 __index 要领,如果 __index 要领为 nil,则返回 nil;如果 __index 要领是一个表,则反复 1、2、3;如果 __index 要领是一个函数,则返回该函数的返回值。
Lua供给两个用来措置惩罚惩罚元表的要领
setmetatable(table, metatable)为表设置元表metatable,不能从Lua中转变其它任何类型的值的元表metatable(使用debug库例外),要这样做的话必需使用C语言的API。
getmetatable(table)获取表的元表metatable东西
元表的元要领有:(下标是__双底线喔)
函数 描述__add 运算符 +
__sub 运算符 -
__mul 运算符 *
__ div 运算符 /
__mod 运算符 %
__unm 运算符 -(取反)
__concat 运算符 ..
__eq 运算符 ==
__lt 运算符 <
__le 运算符 <=
__call 当函数挪用
__tostring 转化为字符串
__index 挪用一个索引
__newindex 给一个索引赋值
__index取下标操纵用于访谒`table[key]
__newindex赋值给指定下标`table[key]=value
__tostring转换成字符串
__call当Lua挪用一个值时挪用
__mode用于弱表`week table
__metatable用于掩护metatable不被访谒
__add
当Lua试图将两个表相加时,会首先查抄两个表之一是否有元素,然后查抄该元表中是否具有一个叫做__add的字段。如果Lua找到了该字段,则会挪用该字段对应的值。这个值就是所谓的“元要领”。
local tbl1 = {1,2,3} local tbl2 = {5,1,1} -- print(#tbl1, #tbl2) -- 无法直接相加两个表 -- printf(tbl1 + tbl2) -- 实现表的相加操纵 mt = {} mt.__add = function(x, y) local result = {} local length = #x for i=1,length do result[i] = x[i] + y[i] end return result end -- test -- 设置表的元表 setmetatable(tbl1, mt) setmetatable(tbl2, mt) -- 执行表的相加操纵 local result = tbl1 + tbl2 -- 循环输出 for k,v in ipairs(result) do print(k, v) end 1 6 2 3 3 4__concat 表连接
-- 表的连接 local tbl1 = {1,2,3} local tbl2 = {2,3,4} -- 实现表的相加操纵 mt = {} mt.__add = function(x, y) local result = {} local length = #x for i=1,length do result[i] = x[i] + y[i] end return result end -- 实现表的连接操纵 mt.__concat = function(x, y) local length = #x local result = {} for i=1,length do result[i] = x[i].."**"..y[i] end return result end -- 设置表的元表 setmetatable(tbl1, mt) setmetatable(tbl2, mt) -- 执行表的连接操纵 local result = tbl1..tbl2 -- 循环输出 for k,v in ipairs(result) do print(k, v) end 1 1**2 2 2**3 3 3**4下面举一个例子,调集运算
使用表table暗示调集,实现调集计算中的并集、交集等。大家看一下写法,体会一下元表的运用
-- 界说调集 Set = {} -- 界说调集的元表 local mt = {} -- 创建调集,按照参数列表值创建新调集 function Set.new(arr) local set = {} setmetatable(set, mt) --创建调集均具有一个不异的元表 for i,v in ipairs(arr) do set[v] = true end return set end -- 求调集并集 function Set.union(x, y) local result = Set.new{} for k,v in pairs(x) do result[k] = true end for k,v in pairs(y) do result[k] = true end return result end -- 求调集交集 function Set.intersection(x, y) -- 创建空调集 local result = Set.new{} for k in pairs(x) do result[k] = y[k] end return result end -- 将调集转换为字符串 function Set.tostring(set) -- 界说存放调集中所有元素的列表 local result = {} for k in pairs(set) do result[#result + 1] = k end return "{"..table.concat(result, ", ").."}" end -- 打印输出调集元素 function Set.print(set) print(Set.tostring(set)) end -- 设置调集元要领 mt.__add = Set.union -- 测试 local set1 = Set.new{10,20,30,40} local set2 = Set.new{30, 1,50} Set.print(set1 + set2) -- {1, 40, 10, 20, 30, 50} Set.print(Set.intersection(set1, set2)) -- {30}__call
温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/web/33267.html