lua学习笔记16:table元表详解

一 table本质
Lua中table本质实际上是个类似HashMap东西。
其元素是很多的Key-Value对,类似iOS中的字典NSDictionary。
如果尝试访问了一个表中并不存在的元素时,就会触发Lua的一套查找机制。
lua“面向对象”就是凭借这个机制实现的。

示例:
local tab = {}
print(tab.key)

输出:nil

因为tab中没有任何元素,当然视图访问其key元素时就会找不到,所以返回nil。

二 元表metatable
元表,即元素列表,是table的一个备查找的元素列表;
当在table中找不到要访问的元素时,就会到它的元表中中区查找。
table的元表我们可以通过函数setmetatable来设置。

示例:
BaseClass = {
	base = 1,
}


DerivedClass = {
	derived = 2,
}
setmetatable(DerivedClass, BaseClass)
print(DerivedClass.base)

输出:
nil

已经设置了元表,还是找不到,这是为什么呢?往下看!



三 元方法__index
上面可以看到即使设置了元表,还是找不到元表中的元素,这是为什么呢?
因为当要在元表中查询元素的时间,并不是在元表中查找元表,而是在元表的__index中查找。


示例

BaseClass = {
	base = 1,
}
BaseClass.__index = BaseClass

DerivedClass = {
	derived = 2,
}
setmetatable(DerivedClass, BaseClass)
print(DerivedClass.base)

输出:
1

另外,__index还可以是函数。
示例:
BaseClass = {
	base = 1
}
BaseClass.__index = function(tab, key)
	if key == "fun" then
		return 1
	else
		return 0
	end
end


DerivedClass = {
	derived = 2,
}
setmetatable(DerivedClass, BaseClass)
print(DerivedClass.fun)
输出:
1


上面的代码可以简写为:
BaseClass = {
	base = 1,
}
DerivedClass = setmetatable({derived = 2}, {__index = BaseClass})
print(DerivedClass.base)


-------------------------------------------------------------------------
BaseClass = {
	base = 1,
}
DerivedClass = setmetatable({derived = 2}, {__index = function(tab, key)
	if key == "fun" then
		return 1
	else
		return 0
	end
end})
print(DerivedClass.fun)

综上所述,可以发现如下规则:
1 __index方法用来确定表在被作为元表时的查找方法。
2 查找表元素时的过程如下:
a.在表中查找,如果找到,返回该元素,找不到则继续;
b.判断该表是否有元表,如果没有元表,返回nil,有元表则继续;
c.判断元表是否有__index方法,如果没有,则返回nil,有则继续查找;
d.如果__index方法是一个表,则重复a、b、c;
e.如果__index方法是一个函数,则返回该函数的返回值。

四 __newindex方法
当我们赋值时, 查找过程跟上面的一样。
如果都没有查找到,就会在元表metatable的__newindex中增加这个元素,然后赋值。


示例
BaseClass = {
	base = 1,
}
BaseClass.__index = BaseClass


NewElement = {}
BaseClass.__newindex = NewElement


DerivedClass = {
	derived = 2,
}
setmetatable(DerivedClass, BaseClass)


DerivedClass.new = 1


print(BaseClass.new)
print(NewElement.new)
print(DerivedClass.new)

输出:
nil
1
nil

因为DerivedClass里没有new,查看__newindex,并把new=1传给了NewElement,并没有给DerivedClass里的new赋值。

五 __call方法
__call 索引, 它允许你把表当函数调用。
示例:
BaseClass = {}
BaseClass.__call = function (BaseClass, a, b)
	return a + b;
end


DerivedClass = {
	derived = 2,
}
setmetatable(DerivedClass, BaseClass)
print(DerivedClass(1, 2))
输出:
3

六 __tostring方法
可以把表转化为string, 非常方便类似print的函数使用。 
BaseClass = {}
BaseClass.__tostring = function (BaseClass)
	local str = "-"
	for k, v in pairs(BaseClass) do
		str = str..">"..k..":"..v..""
	end
	return str
end


DerivedClass = {
	className = "DerivedClass",
	derived = 2,
}
setmetatable(DerivedClass, BaseClass)
print(DerivedClass)

输出:
->derived:2>className:DerivedClass

你可能感兴趣的:(lua,元表)