第一版是为 Lua 5.0 编写的。虽然在很大程度上仍然适用于后续版本,但有一些区别。
第四版针对 Lua 5.3,可在 Amazon 和其他书店购买。
购买本书,您还可以帮助 支持 Lua 项目。
![]() |
用 Lua 编程 | ![]() |
| 第二部分。表和对象 第 13 章。元表和元方法 |
__index 元方法我之前说过,当我们访问表中不存在的字段时,结果是 nil。这是真的,但并不是全部。实际上,这种访问会触发解释器查找 __index 元方法:如果没有这种方法(通常如此),则访问结果为 nil;否则,元方法将提供结果。
这里的典型示例是继承。假设我们要创建几个描述窗口的表。每个表都必须描述几个窗口参数,例如位置、大小、配色方案等。所有这些参数都有默认值,因此我们希望仅给出非默认参数来构建窗口对象。第一个备选方案是提供一个填充不存在字段的构造函数。第二个备选方案是安排新窗口从原型窗口继承任何不存在的字段。首先,我们声明原型和构造函数,它创建共享元表的窗口
-- create a namespace
Window = {}
-- create the prototype with default values
Window.prototype = {x=0, y=0, width=100, height=100, }
-- create a metatable
Window.mt = {}
-- declare the constructor function
function Window.new (o)
setmetatable(o, Window.mt)
return o
end
现在,我们定义 __index 元方法
Window.mt.__index = function (table, key)
return Window.prototype[key]
end
在该代码之后,我们创建一个新窗口并查询不存在的字段
w = Window.new{x=10, y=20}
print(w.width) --> 100
当 Lua 检测到 w 没有请求的字段,但有一个具有 __index 字段的元表时,Lua 会调用此 __index 元方法,参数为 w(表)和 "width"(不存在的键)。然后,元方法使用给定的键对原型进行索引并返回结果。
__index 元方法用于继承非常常见,因此 Lua 提供了一个快捷方式。尽管名称为 __index,但元方法不必是函数:它可以是表。当它是一个函数时,Lua 会使用表和不存在的键作为其参数来调用它。当它是一个表时,Lua 会在该表中重新进行访问。因此,在我们的前一个示例中,我们可以简单地将 __index 声明为
Window.mt.__index = Window.prototype现在,当 Lua 查找元表的
__index 字段时,它会找到 Window.prototype 的值,它是一个表。因此,Lua 会在此表中重复访问,即执行等效于
Window.prototype["width"]这会给出所需的结果。
将表用作 __index 元方法提供了一种实现单一继承的廉价且简单的方法。函数虽然开销更大,但提供了更大的灵活性:我们可以实现多重继承、缓存和许多其他变体。我们将在 第 16 章 中讨论这些继承形式。
当我们想要访问表而不调用其 __index 元方法时,我们使用 rawget 函数。调用 rawget(t,i) 对表 t 执行原始访问。执行原始访问不会加快代码速度(函数调用的开销会抵消任何收益),但有时您需要它,正如我们稍后将看到的。
| 版权所有 © 2003–2004 Roberto Ierusalimschy。保留所有权利。 | ![]() |