首页 > 代码库 > Lua 笔记--元表与元方法

Lua 笔记--元表与元方法

        可以通过元表来修改一个值的行为,使其在面对一个非预定义的操作时执行一个指定的操作。当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 
end
function 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 res
end
function Set.intersection( a, b )
	local res = Set.new{}
	for k in pairs(a) do res[k] = b[k] end 
	return res 
end
function Set.tostring( set )
	local l = {}
	for e in pairs(set) do l[#l + 1] = e end 
	return "{" ..table.concat(l, ", ") .. "}"		
	--table.concat函数会将给定列表中的所有字符串连接起来,并返回连接结果
end
function Set.print( s )
	print(Set.tostring(s))
end
s1 = Set.new{1, 2, 3, 4}
s2 = Set.new{2, 5}
--两个集合具有一个相同的元表
print(getmetatable(s1))		-->table: 0x7fee11c09940
print(getmetatable(s2))		-->table: 0x7fee11c09940
--将元方法加入元表中。
mt.__add = Set.union 
--当Lua试图将两个集合相加时,就会调用Set.union函数,并将两个操作数作为参数传入
s3 = s1 + s2
Set.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 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
s1 = Set.new{2, 4}
s2 = Set.new{2, 4, 8}
print(s1 <= s2)		-->true
print(s1 < s2)		-->true
print(s1 >= s2)		-->false
print(s1 > s2)		-->false
print(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 o
end
--定义__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元方法。如果有这个元方法,解释器就调用它,而不是执行赋值。




Lua 笔记--元表与元方法