lua - 在原型“构造函数”内部或外部定义 __index
问题描述
我正在阅读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 上做了一些“sintetic benchmarks”,在一个简单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
条目,这个条目只是在b
的元表中。如果您仍想避免__index
在“构造函数”中声明,则需要在每个派生原型或“子类”中指定它。
解决方案
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
推荐阅读
- php - Laravel 雄辩与查询构建器的优缺点
- c# - 如何从其他页面初始化 ShellView(Windows 模板工作室)
- r - 从闪亮的服务器运行 python 脚本
- react-native - react-navigation : 如何隐藏一个特定的 tabBar 图标和标签
- oracle-jet - 从 oj.Collection 或 oj.Model 传递请求标头
- mysql - 如何撤销 MySQL 用户的权限
- google-play-console - 创建生产版本后,在 Play 商店中找不到应用
- swiftui - SwiftUI '(String) -> Image' 不能转换为 '(String, Bundle?) -> Image'
- rust - 包装一个借用东西的结构
- python-3.x - 如何使用 tkinter 中的按钮更改菜单的状态?