示例代码:
function Account:new (o)
o = o or {} -- create object if user does not provide one
setmetatable(o, self)
self.__index = self
return o
end
取自:
http://www.lua.org/pil/16.1.html
目的是什么:
self.__index = self
行?为什么每次创建对象时都会执行它?
答案 0 :(得分:5)
正如其他人所说,self
(Account
表)用作分配给使用new
创建的对象的元表。当在“o”中找不到字段时,稍微简化(在提供的链接上提供更多信息),它会转到“帐户”表,因为o的metatable表示转到帐户(这是__index
所做的)。
但是,每次创建对象时都不需要执行它。你可以很容易地把它粘在某个地方:
Account.__index = Account
它也可以。
更长的故事是,如果对象o
具有元表,并且该元表具有__index
字段集,则{{1> 字段查找{{1}将使用o
来查找字段(__index
可以是表或函数)。如果__index
设置了字段,则不会转到其metatable的o
函数来获取信息。不过,我再次鼓励您阅读上面提供的链接。
答案 1 :(得分:4)
Lua文档在这个细节上有点模糊,这里的许多答案要么回应Lua文档,要么没有彻底解释这个令人困惑的小问题。
行self._index = self
纯粹是为了新创建的对象o
的利益而存在;它对Account
没有任何意义或功能影响。
_index
字段在元表的上下文中只有特殊含义;因此self._index
只是Account
的普通旧常规字段。但是,当Account
用作o
的元表时,_index
字段“变为”o
的元方法。 (那么Account
的字段是o
的元方法。)
当您将这两个陈述合并时......
(1) setmetatable(o, self) (2) self._index = self
...您在第(1)行使用Account
作为o
的元表,并将_index
的{{1}}元方法设为o
在第(2)行。 (在第(2)行,您还要将Account
中的“普通旧字段”__index
设置为Account
。)因此Account
的有用方面不是self._index = self
的{{1}}字段的设置,而是_index
的{{1}}元方法的设置。
以下功能相同:
setmetatable(o, self) getmetatable(o)._index = self
答案 2 :(得分:3)
Lua不是面向对象的语言,但它具有编写面向对象代码的所有功能。但是,它以prototyping方式和JavaScript完成。不是显式创建类,而是创建原型对象,然后克隆以创建新实例。
当表中的密钥尚未存在时,将调用__index
元方法对表的读访问执行密钥查找。因此,self.__index = self
基本上允许通过Account
和o = o or {}
行中创建的新“实例”继承setmetatable(o, self)
“类”的所有方法和字段。
另见:
答案 3 :(得分:0)
它们用于重定向表访问(本地y = table [key]),这些访问也用于方法调用。在上面的行中,对象o将尝试访问重定向到当前对象self的键,毫不费力地继承所有成员函数。也可能是数据变量,具体取决于__index究竟是什么以及它是如何工作的。
答案 4 :(得分:0)
创建对象(简称为Tables)与Lua完全不同。 基本思想是创建一个包含所有实例共有的属性(函数和值)的常规表。这个表,我将称为公共属性表的CAT。
如果你在表中引用一个属性而Lua找不到这个属性,那么就有办法告诉Lua在哪里寻找属性。我们希望Lua在CAT中查找常用属性。 Metatables回答了这个需求。更多关于以后的工作方式。
我们还需要CAT中的方法才能使用实例值。 自我需要的答案。当您以这种方式调用表函数(方法):tableName:methodName()
时,Lua会自动将对象的引用作为第一个参数。此参数的名称为self。即使该方法位于CAT中,self也将引用特定的调用对象实例表。
假设我们有一个叫做Car的CAT。
metaCar = { __index = Car }
-- this table will be used as the metatable for all instances of Car
-- Lua will look in Car for attributes it can't find in the instance
例如:
-- instance table is called mustang
-- setmetatable(mustang, metaCar)
这是一个通用函数,它创建新的实例对象并为其设置元表。如果CAT具有构造函数(init),它也会被执行。
function newObj(metatable)
..obj = {} -- create new empty instance object
..setmetatable(obj, metatable) –- connect the metatable to it
..if obj.init then -- if the CAT has an init method, execute it
....obj:init()
..end
..return obj
end
答案 5 :(得分:0)
请注意,setmetatable(o, self)
仅将Account设置为o
的元表(否则默认为 nil )。这是原型绑定的第一步,但还还不足以使Account功能可以从o
进行搜索!
要在Account上使用o
个搜索方法,该元表对象(Account)必须包含一个__index
事件,该事件的值指向自身,其中包含原型方法。
所以必须分两个步骤完成
:__index
事件创建一个元表值如原始书籍中所述,这是“一个小的优化”-您通常需要创建另一个模具表值作为o
的元表。但是在这种情况下,代码重新使用了Acccount表值,将其作为元表和原型对象。