本文共 2418 字,大约阅读时间需要 8 分钟。
可以通过元表来修改一个值的行为,使其在面对一个非预定义的操作时执行一个指定的操作。当Lua试图将两个table相加时,它会先检查两者之一是否有元表,然后检查该原表中是否有一个叫__add的字段。
Lua在创建新的table时不会创建元表,可以使用setmetatable来设置或修改任何table的元表。
在Lua中,只能设置table的元表,若要设置其他类型的值的元表,则必须通过C代码来完成。其他类型在默认情况下都没有元表。
1、算术类的元方法
Set = {}local mt = {}--根据参数列表中的值创建一个新的集合function Set.new( l ) local set = {} setmetatable(set, mt) --将mt设置为当前所创建table的元表 for _, v in ipairs(l) do set[v] = true end return set endfunction Set.union( a, b ) 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 resendfunction Set.intersection( a, b ) local res = Set.new{} for k in pairs(a) do res[k] = b[k] end return res endfunction Set.tostring( set ) local l = {} for e in pairs(set) do l[#l + 1] = e end return "{" ..table.concat(l, ", ") .. "}" --table.concat函数会将给定列表中的所有字符串连接起来,并返回连接结果endfunction Set.print( s ) print(Set.tostring(s))ends1 = Set.new{1, 2, 3, 4}s2 = Set.new{2, 5}--两个集合具有一个相同的元表print(getmetatable(s1)) -->table: 0x7fee11c09940print(getmetatable(s2)) -->table: 0x7fee11c09940--将元方法加入元表中。mt.__add = Set.union --当Lua试图将两个集合相加时,就会调用Set.union函数,并将两个操作数作为参数传入s3 = s1 + s2Set.print(s3) -->{1, 2, 3, 4, 5}--类似的,还可以使用乘号来求集合的交集mt.__mul = Set.intersection Set.print((s1 + s2) * s1) -->{1, 2, 3, 4}--[[在元表中,每种算术操作符都有对应的字段名。除了__add 和__mul外,还有__sub(减法)、__div(除法)、__unm(相反数)、__mod(取模)、__pow(乘幂)。此外,还可以定义__concat字段,用于描述连接操作符的行为。]]
2、关系类的元方法
mt.__le = function ( a, b ) --集合包含 for k in pairs(a) do if not b[k] then return false end end return trueendmt.__lt = function ( a, b ) return a <= b and not (b <= a)endmt.__eq = function ( a, b ) return a <= b and b <= a ends1 = Set.new{2, 4}s2 = Set.new{2, 4, 8}print(s1 <= s2) -->trueprint(s1 < s2) -->trueprint(s1 >= s2) -->falseprint(s1 > s2) -->falseprint(s1 == s2 * s1) -->true
3、table访问的元方法
--[[当访问一个table中不存在的字段时,会促使解释器去查找一个叫__index的元方法。如果没有这个元方法,那么访问结果为nil,否则就由这个元方法来提供最终结果。]]Window = {} --创建一个名字空间--使用默认值来创建一个原型Window.prototype = {x=0, y=0, width=100, height=200}Window.mt = {} --创建元表 --声明构造函数function Window.new( o ) setmetatable(o, Window.mt) return oend--定义__index元方法Window.mt.__index = function ( table, key ) return Window.prototype[key]end--__index不必是一个函数,还可以是一个table--Window.mt.__index = Window.prototype--创建一个新窗口,并查询一个它没有的字段w = Window.new{x = 10, y = 20}print(w.width) -->100
__newindex元方法与__index元方法类似,不同之处在于前者用于table的更新,而后者用于table的查询。当对一个table中不存在的索引赋值时,解释器就会查找__newindex元方法。如果有这个元方法,解释器就调用它,而不是执行赋值。
转载地址:http://jvbzx.baihongyu.com/