一 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方法,如果找到,则使用__newindex的值,没找到__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