在原型 "constructor" 内部或外部定义 __index
Define __index inside prototype "constructor" or outside
我正在 https://www.lua.org/pil/16.html 上阅读“Lua 编程”中的“面向对象编程”一章。
在那个例子中,他们创建了这个“构造函数”:
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
在一个脚本中做了一些“sintetic 基准测试”,该脚本有 1000 万次这样的操作。在 table 初始化之外定义 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
会有元 table 和 b
一样 table,但是 b
没有 __index
条目,此条目仅在b
的元table中。
如果您仍想避免在“构造函数”中声明 __index
,则需要在每个派生原型或“子类”中指定它。
PiL 的作者似乎试图通过让 new
方法像处理所有 child 一样处理根 object 来简化事情 objects。这可能会让初学者感到困惑,因为不能立即清楚 self.__index = self
通常是多余的。
此外,这样做实际上比在每个 object 上添加一个 __index
更快。请记住,在原型系统中,每个 object 都可能是其他 object 的原型。在我的机器上,通过 1e8 次试验,PiL 方式需要 14 秒,而将 __index
添加到所有 object 需要 23 秒。新密钥意味着 table 必须增长,因此它比分配给已存在的密钥慢。
令人困惑的是,这个 PiL 部分的标题是“类”,但在第一段中,他说他正在模拟 prototype-based 种语言,其中“object 没有 class是的。”这进一步搞砸了 reader 的期望。本节实现 self-replicating object,而不是 class.
下面是我的实现方式,虽然不那么令人困惑,但速度较慢:
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
我正在 https://www.lua.org/pil/16.html 上阅读“Lua 编程”中的“面向对象编程”一章。
在那个例子中,他们创建了这个“构造函数”:
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
在一个脚本中做了一些“sintetic 基准测试”,该脚本有 1000 万次这样的操作。在 table 初始化之外定义 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
会有元 table 和 b
一样 table,但是 b
没有 __index
条目,此条目仅在b
的元table中。
如果您仍想避免在“构造函数”中声明 __index
,则需要在每个派生原型或“子类”中指定它。
PiL 的作者似乎试图通过让 new
方法像处理所有 child 一样处理根 object 来简化事情 objects。这可能会让初学者感到困惑,因为不能立即清楚 self.__index = self
通常是多余的。
此外,这样做实际上比在每个 object 上添加一个 __index
更快。请记住,在原型系统中,每个 object 都可能是其他 object 的原型。在我的机器上,通过 1e8 次试验,PiL 方式需要 14 秒,而将 __index
添加到所有 object 需要 23 秒。新密钥意味着 table 必须增长,因此它比分配给已存在的密钥慢。
令人困惑的是,这个 PiL 部分的标题是“类”,但在第一段中,他说他正在模拟 prototype-based 种语言,其中“object 没有 class是的。”这进一步搞砸了 reader 的期望。本节实现 self-replicating object,而不是 class.
下面是我的实现方式,虽然不那么令人困惑,但速度较慢:
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