尝试理解这段Lua代码片段。
我正在尝试理解这个函数的作用。有人可以给我解释一下吗?
function newInstance (class)
local o = {}
setmetatable (o, class)
class.__index = class
return o
end
它被这样调用:
self = newInstance (self)
原文链接 https://stackoverflow.com/questions/9616606
这被用于在 Lua 中实现面向对象的行为。Lua 使用基于原型的继承(类似于 Javascript),而不是基于类的继承(如Java或C++)。
思路是将所有类方法实现为原型对象的一部分,并且继承对象在调用时委托给原型。
例如,假设你想要一个名为 myClass
的类,提供一个名为 getMagicNumber
的方法:
local myClass = {
getMagicNumber = function(self)
return self.theNumber;
end };
local obj = newInstance(myClass);
obj.theNumber = 42;
print(obj:getMagicNumber()); -- 应该返回42
这是一个非常简单的例子,但我希望你能够理解。发生的事情是:newInstance
创建一个新的表,并将其元表指向 myClass
,并且还确保元表的 __index
字段也指向 myClass
。
正如 Lua 手册中关于 __index
所描述的那样,当您现在尝试在新表上调用 getMagicNumber
时,以下内容会发生:首先 Lua 会在 obj
表中查找 getMagicNumber
字段。由于该表为空,因此现在它在其 __index
表(myClass
)中搜索该字段。由于在那里找到了该字段,因此现在调用在 myClass
中找到的函数。
《Lua 程序设计》 在需要了解更多内容时详细讨论了此机制。
你并不孤单,我花了相当长的时间才理解这个代码。这是我的解释:
每个表都可以有一个元表,元表可以储存许多东西,其中包括按名称索引的函数。setmetatable
函数用自然的方式设置元表的值。
class._index = ...
这行是魔法发生的地方。
当你试图使用 self.fn1()
调用一个函数时,Lua会在 self
中查找一个名为 fn1
的名称。 如果它找不到它,则会在self
的元表中查找一个表 __index
,并在其中存储的表中查找“fn1”。
现在,在你的示例中,self
的元表是 class
,因此Lua查找元表(class
)中的 __index
条目,以查看是否在该表中有一个名为 fn1
的函数,如果有,则返回它。 你需要将 class
上的 __index
设置回自身,这样Lua就会在同一个元表中查找 - 这很令人困惑。
(顺便说一下,对 __index
的赋值只需要发生一次,但由于某些原因,在所有Lua示例中都在new
操作符中执行 - 在我的类中,我将其移到 new
之外 - 可以节约一些循环次数)
然后你返回新表 o
,Lua有垃圾收集机制,因此每次返回一个本地变量都会创建一个新表。
function newInstance (class)
local o = {}
setmetatable (o, class)
class.__index = class
return o
end
- 如何在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 模式将字符串(嵌套数组)转换为真正的数组?
这个函数显然用于在 Lua 中提供一种 OOP 变体(在我看来有点松散)。
这是一个类的工厂。
为了更清晰,它可以被重写为以下形式:
C = {} C.foo = function(self) -- just some method, so class would not be empty print("foo method called", tostring(self)) end C.__index = C -- (A) function newInstance(class) return setmetatable({}, class) -- (B) end
现在如果我们创建两个 C 的实例,我们可以清楚看到它们都有一个 foo() 方法,但是不同的 self:
o1 = newInstance(C) o1:foo() --> foo method called table: 0x7fb3ea408ce0 o2 = newInstance(C) o2:foo() --> foo method called table: 0x7fb3ea4072f0
foo 方法是相同的:
print(o1.foo, o2.foo, o1.foo == o2.foo and "equal" or "different") --> function: 0x7fb3ea410760 function: 0x7fb3ea410760 equal
这是因为表 C(“类”)是 o1 和 o2 的 metatable 的 __index(上面的
(A)
),设置为(B)
中的类实例或对象。注意:我们在
(A)
中将C.__index
设置为等于C
本身,这样我们就可以重用一个表。以下代码具有相同的效果:prototype = {} prototype.foo = function(self) -- just some method, so class would not be empty print("foo method called", tostring(self)) end C = {__index = prototype} function newInstance(class) return setmetatable({}, class) end o = newInstance(C)