在Lua中进行编程,对象
该行代码的目的是将实例对象的索引指向其所属的类,以便在实例对象中查找属性和方法时能够自动调用类中定义的属性和方法。它在每次创建对象时都被执行,以确保每个对象都有正确的索引。
原文链接 https://stackoverflow.com/questions/2761713
Lua 不是面向对象的语言,但它具备编写面向对象代码的所有设施。然而,它是按照 JavaScript 风格的原型(prototyping
)方式实现的。与显式创建类不同,先创建一个原型对象,然后克隆它以创建新实例。
当键不存在于表中时,__index
元方法被调用以在读取表中的值时执行键查找。因此,self.__index = self
本质上允许通过 o = o or {}
和 setmetatable(o, self)
行创建的新“实例”继承 Account
类的所有方法和字段。
另请参阅:
正如其他人所说的那样,self
(即Account
表)被用作分配给使用new
创建的对象的元表。稍微简化一下(更多信息可在提供的链接中找到),当在'o'中找不到字段时,它会转到'Account'表,因为o的元表要求转到Account(这就是__index
的作用)。
然而,它并不需要在每次创建对象时执行。你同样可以把它放在别处:
Account.__index = Account
这也能起到相同的作用。
稍微详细一点的解释是,如果一个对象o
具有元表,并且元表具有设置__index
字段,那么在o
上执行的一个字段查找失败将使用__index
来找到该字段(__index
可以是表或函数)。如果o
具有该字段,你不会去到它的元表的__index
函数来获取信息。同样,我建议您在上面提供的链接中阅读更多。
Lua文档在这一细节上有点含糊,这里的许多答案要么 echo Lua文档,要么没有彻底解释这个令人困惑的要点。
行 self._index = self
仅出现是为了新创建的对象 o
的好处;它对 Account
没有任何有意义或有功能性的影响。
_index
字段在元表上下文中才具有特殊含义;因此,self._index
对于 Account
只是一个普通的常规字段。然而,当 Account
用作 o
的元表时,_index
字段“变成”了 o
的元方法。因此,对于 Account
的字段是 o
的元方法。
当你将两个语句结合在一起...
(1) setmetatable(o, self)
(2) self._index = self
...你正在将 Account
用作第(1)行中的 o
的元表,并在第(2)行中将 o
的 _index
元方法设置为 Account
。在第(2)行中,您还将 Account
中的“普通旧字段”__index
设置为 Account
。因此,self._index = self
的有用方面不是为 Account
设置 _index
字段,而是为 o
设置 _index
元方法。
下面的代码与上述代码功能相同:
setmetatable(o, self)
getmetatable(o)._index = self
在 Lua 中创建对象(简单来说就是表格)与其他语言不太相同。基本思想是创建一个普通的表格,其中包含所有实例共有的属性(函数和值)。我将这个表格称为 CAT(即公共属性表格)。
如果在一个表格中引用一个属性,而 Lua 找不到该属性,有一种方法可以告诉 Lua 在哪里查找该属性。我们希望 Lua 在 CAT 中查找共同的属性。元表就是这样的答案。后面会详细介绍它的工作原理。
我们还需要在 CAT 中设置方法以便使用实例的值。Self 也是答案。当您这样调用一个表格函数(方法):tableName:methodName()
时,Lua 会自动将对表格对象的引用作为第一个参数。这个参数的名称是 self。尽管该方法位于 CAT 中,但 self 将引用特定的调用对象实例表。
假设我们有一个名为 Car 的 CAT。
metaCar = { __index = Car }
-- 这个表格将用作 Car 的所有实例的元表
-- Lua 会在实例中查找不到的属性在 Car 中查找
例如:
-- 实例表格称为 mustang
-- setmetatable(mustang, metaCar)
以下是一个通用函数,它创建新的实例对象并设置它的元表。如果 CAT 有一个构造函数(init),它也会执行。
function newObj(metatable)
..obj = {} -- 创建新的空实例对象
..setmetatable(obj, metatable) –- 将元表连接到它上面
..if obj.init then -- 如果 CAT 有一个 init 方法,执行它
....obj:init()
..end
..return obj
end
请注意 setmetatable(o, self)
只是将 o
设置为 Account
的元表(默认为 nil)。这是原型绑定的第一步,但这还 不足以 使 o
从 Account
中搜索方法!
要使 o
搜索 Account
的方法,元表对象(Account
)必须包含一个具有指向自身的值的 __index
事件,其中包含原型方法。
因此需要分两步完成:
- 创建具有
__index
事件的元表值 - 将元表设置为目标表。
如原书所述,这是“一个小优化”,通常您需要创建另一个模板表值作为 o
的元表。但在这种情况下,代码重用了 Account
表值,作为元表和原型对 象。
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
他们用于重定向表访问(
local y = table[key]
),这也在方法调用中使用。在上面那行中,对象o
将会把访问键的任何尝试重定向到当前对象self
,从而毫不费力地继承所有成员函数。也可能继承数据变量,这取决于__index
是什么,以及它如何工作。