在学习Lua语言的元表和元方法章节中,各种网上收例子,便于理解学习。
看到一篇很好的博客,讲到了 lua 的 rawset,rawget,index,newindex的使用,具体博客见下面链接:
作者:@qingqing-zhao
本文为作者原创,转载请注明出处:https://www.cnblogs.com/zhaoqingqing/archive/2018/11/28/10032249.html
在开头的一段代码中,作者留一下一个问题:
设置过__newindex之后,就不会调用__index了?
然后我将作者的例子,自己在linux lua5.1 环境下执行了一遍,并加些log,且能属性table中的具体元素,这样就能看到是否在执行下面这一句时,真没进到 __index函数中去:
print(tb.server)
测试代码如下:
local tb = {}
setmetatable(tb, { __index = function()
print("__index 000000")
return "not find"
end })
setmetatable(tb, {
__newindex = function(table, key, value)
local patchKey = "version"
print("__newindex 11111111111")
if key == patchKey then
print("__newindex 2222222222222")
rawset(table, patchKey, "patch value")
else
print("__newindex 3333333333333")
rawset(table, key, value)
end
end })
print("111 table tb:")
PrintTable(tb)
tb.version = "normal version"
tb.date = "2018"
print(tb.version) --打印 补丁值
print("\n")
print("111111111-----")
print(tb.server) --打印nil,不会调用__index方法了?
print("222222222-----")
print("\n")
print(tb.date) --打印2018
print("222 table tb:")
PrintTable(tb)
执行结果如下:
111 table tb:
{
}
__newindex 11111111111
__newindex 2222222222222
__newindex 11111111111
__newindex 3333333333333
patch value
111111111-----
nil
222222222-----
2018
222 table tb:
{
version = patch value
date = 2018
}
的确如作者所说,在 执行下面这一行,真没有调用 __index方法,
print(tb.server) --打印nil,不会调用__index方法了?
根据作者提出的问题,我再网上查了老半天,也没有看到能解释这种现象的。
但就在午饭时,不经意看代码发现,作者的代码上面,执行了两次 setmetatable操作,会不会第二次将第一次的 setmetatable
中的 __index 给覆盖掉了? 是不是lua的 table 只能设置一次setmetatable?
如是,我将__index和__newindex移到了一起,在一个 setmetatable进行设置,代码如下:
local tb = {}
-- setmetatable(tb, { __index = function()
-- print("__index 000000")
-- return "not find"
-- end })
setmetatable(tb, {
__index = function()
print("__index 000000")
return "not find"
end,
__newindex = function(table, key, value)
local patchKey = "version"
print("__newindex 11111111111")
if key == patchKey then
print("__newindex 2222222222222")
rawset(table, patchKey, "patch value")
else
print("__newindex 3333333333333")
rawset(table, key, value)
end
end })
print("111 table tb:")
PrintTable(tb)
tb.version = "normal version"
tb.date = "2018"
print(tb.version) --打印 补丁值
print("\n")
print("111111111-----")
print(tb.server) --打印nil,不会调用__index方法了?
print("222222222-----")
print("\n")
print(tb.date) --打印2018
print("222 table tb:")
PrintTable(tb)
再次执行结果如下:
111 table tb:
{
}
__newindex 11111111111
__newindex 2222222222222
__newindex 11111111111
__newindex 3333333333333
patch value
111111111-----
__index 000000
not find
222222222-----
2018
222 table tb:
{
version = patch value
date = 2018
}
修改为如上,代码,则作者提出的问题就不会出现,
print(tb.server) 就会调用 _index 的函数,打印: not find
但提出了新问题:
lua 中table的setmetatable是不是只能设置一次? 多次设置是不是只有最后的一次设置才有效?
这些问题,目前还在查找和验证中,
非常感谢那篇博主的文章,让我学到不少东西,加深理解元表。
同时发现书中所说的字符串的元表都是相同的一个,验证也确实是:
local str00 = "Hello"
local str01 = "World"
print(getmetatable(str00))
print(getmetatable(str01))
输出结果:
table: 0x14eb490
table: 0x14eb490