尝试理解这段Lua代码片段。

我正在尝试理解这个函数的作用。有人可以给我解释一下吗?

function newInstance (class)
    local o = {}
    setmetatable (o, class)
    class.__index = class
    return o
end

它被这样调用:

self = newInstance (self)

原文链接 https://stackoverflow.com/questions/9616606

点赞
stackoverflow用户6236
stackoverflow用户6236

这个函数显然用于在 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)
2012-03-08 12:59:36
stackoverflow用户577603
stackoverflow用户577603

这被用于在 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 程序设计》 在需要了解更多内容时详细讨论了此机制。

2012-03-08 13:04:38
stackoverflow用户416047
stackoverflow用户416047

你并不孤单,我花了相当长的时间才理解这个代码。这是我的解释:

每个表都可以有一个元表,元表可以储存许多东西,其中包括按名称索引的函数。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
2012-03-09 04:01:06