我对使用"。"
的以下两种语法感到困惑根据我的理解,当一个密钥不存在于表中但存在于其元表中时,会调用__index
。那么为什么列表会调用__index
然后将自己分配给list.__index
?
list = {}
list.__index = list
setmetatable(list, { __call = function(_, ...)
local t = setmetatable({length = 0}, list)
for _, v in ipairs{...} do t:push(v) end
return t
end })
function list:push(t)
if self.last then
self.last._next = t
t._prev = self.last
self.last = t
else
self.first = t
self.last = t
end
self.length = self.length + 1
end
.
.
.
local l = list({ 2 }, {3}, {4}, { 5 })
Window.mt
只是创建一个表吗?为什么我们需要Window = {}
作为命名空间?
Window = {} -- create a namespace
Window.mt = {} -- create a metatable
Window.prototype = {x=0, y=0, width=100, height=100, }
function Window.new (o)
setmetatable(o, Window.mt)
return o
end
Window.mt.__index = function (table, key)
return Window.prototype[key]
end
w = Window.new{x=10, y=20}
print(w.width) --> 100
答案 0 :(得分:5)
在您的代码中没有任何地方列表调用 __index
。然而,赋值部分是一个常见的Lua习语(又名.hack)来节省一些内存。从概念上讲,涉及4种不同的表:
{length=0}
创建的表)__index
字段),当您尝试访问对象中不存在的字段时,它会修改列表对象的行为list
类,它包含列表对象的所有方法(如push
方法),也可用作列表对象的构造函数 __call
类的元表(包含list
字段),以便您可以将list
表调用为函数
由于可元化字段始终以两个下划线(__
)开头,而常规方法通常不会,您可以将可元素字段和常规方法并排放入单个表中而不会发生冲突。这就是这里发生的事情。 list
类表也可用作列表对象的元表。因此,使用此技巧可以节省通常需要用于单独metatable的内存(x86-64 Linux上Lua 5.2的字节大小显示在表标题栏的方括号中,顺便说一句。)
不,{}
创建一个表。但是,此新表格保存在"mt"
表格中的密钥Window
下,可能是为了给这个Window
"类"直接访问用于窗口对象的元表。只给出你展示的代码,这不是绝对必要的,你可以使用局部变量。
原则上,您可以单独存储Window.mt
,Window.new
和Window.prototype
,但如果您有多个"类,那将会很麻烦。比如Window
。通过这种方式,您可以避免名称冲突,并使用Window
"类"看起来更好。
另一个原因可能是require
只能从模块定义返回单个值,并且如果要导出多个值(例如new
,mt
和{{1从模块中,你需要一个表将它们包装在一起(或使用全局变量,但这被认为是不好的样式)。