在原型“构造函数”内部或外部定义 __index

时间:2021-04-11 15:46:48

标签: lua

我正在阅读 https://www.lua.org/pil/16.html 上的“Programming in Lua”中的“Object-Oriented Programming”一章。

在那个例子中,他们创建了这个“构造函数”:

Account = {balance = 0}
function Account:new (o)
  o = o or {}   -- create object if user does not provide one
  setmetatable(o, self)
  self.__index = self
  return o
end

我在 Linux 上用一个简单的 time 进行了一些“简单的基准测试”,脚本中包含 1000 万次这样的操作。在表初始化之外定义 Account.__index = Account 快 200 毫秒。

我的问题是,如果我们可以在外部定义并执行一次,为什么将self.__index设置在每次调用此函数时都会执行的函数内部?也许是遗产?

已编辑:

感谢 luther 的回答,我将在这里为有此疑问的每个人创建一个示例:

local a = {}
a.__index = a
function a:foo()
    return 'foo'
end

function a:new(o)
    print(self)
    o = o or {}
    setmetatable(o, self)
    -- self.__index = self
    return o
end

local b = a:new()
-- b.__index = b
function b:bar()
    return 'bar'
end

local z = a:new()
print(z:foo()) -- this will work

local y = b:new()
print(y:foo()) -- attempt to call method 'foo' (a nil value)
print(y:bar()) -- attempt to call method 'bar' (a nil value)

当然y会有一个带有b的元表作为那个表,但是b没有__index条目,这个条目只在{{1}里面}} 的元表。 如果您仍想避免在“构造函数”中声明 b,则需要在每个派生原型或“子类”中指定它。

1 个答案:

答案 0 :(得分:3)

PiL 的作者似乎试图通过让 new 方法像处理所有子对象一样处理根对象来简化事情。这可能会让初学者感到困惑,因为还不清楚 self.__index = self 通常是多余的。

此外,这样做实际上比向每个对象添加 __index 更快。请记住,在原型系统中,每个对象都可能是其他对象的原型。在我的机器上,通过 1e8 次试验,PiL 方式需要 14 秒,而向所有对象添加 __index 需要 23 秒。新键意味着表必须增长,因此比分配给已存在的键要慢。

令人困惑的是,这个 PiL 部分的标题是“类”,但在第一段中,他说他正在模拟基于原型的语言,其中“对象没有类”。这进一步破坏了读者的期望。本节实现了一个自我复制的对象,而不是一个类。

这是我不太容易混淆但较慢的实现:

Account = {balance = 0}
Account.__index = Account

function Account:new (o)
  o = o or {}   -- create object if user does not provide one
  setmetatable(o, self)
  o.__index = o
  return o
end
相关问题