__index 元方法

简介: __index 元方法

正如我们之前所看到的,当访问一个表中不存在的字段时会得到 nil 。这是正确的,但不是完整的真相。实际上,这些访问会引发解释器查找一个名为 __index 的元方法。如果没有这个元方法,那么像一般情况下一样,结果就是 nil ;否则,则由这个元方法来提供最终结果。


下面介绍一个关于继承的原型示例。假设我们要创建几个表来描述窗口,每个表中必须描述窗口的一些参数,例如位置、大小及主题颜色等。所有的这些参数都有默认值,因此我们希望在创建窗口对象时只需要给出那些不同于默认值的参数即可。第一种方法是使用一个构造器来填充不存在的字段,第二种方法是让新窗口从一个原型窗口继承所有不存在的字段。首先,我们声明一个原型:

-- 创建具有默认值的原型
prototype = {x = 0, y = 0, width = 100, height = 100}


然后,声明一个构造函数,让构造函数创建共享同一个元表的新窗口:

local mt = {}     -- 创建一个元表
-- 声明构造函数
function new (o)
  setmetatable(o, mt)
  return o
end


现在,我们来定义元方法 __index

mt.__index = function (_, key)
  return prototype[key]
end


在这段代码后,创建一个新窗口,并查询一个创建时没有指定的字段:

w = new{x = 10, y = 20}
print(w.width)    --> 100


Lua 语言会发现 w 中没有对应的字段 "width" ,但却有一个带有 __index 元方法的元表。因此, Lua 语言会以 w (表)和 "width" (不存在的键)为参数来调用这个元方法。元方法随后会用这个键来检索原型并返回结果。


Lua 语言中,使用元方法 __index 来实现继承是很普遍的方法。虽然被叫做方法,但元方法 __index 不一定必须是一个函数,它还可以是一个表。当元方法是一个函数时, Lua 语言会以表和不存在的键为参数调用该函数,正如我们刚刚看到的。当元方法是一个表时, Lua 语言就访问这个表。因此,在我们此前的示例中,可以把 __index 简单地声明为如下样式:

mt.__index = prototype


这样,当 Lua 语言查找元表的 __index 字段时,会发现字段的值是表 prototype 。因此, Lua 语言就会在这个表中继续查找,即等价地执行 prototype["width"] ,并得到预期的结果。


将一个表用作 __index 元方法为实现带继承提供了一种简单快捷的方法。虽然将函数用作元方法开销更昂贵,但函数却更加灵活:我们可以通过函数来实现多继承缓存及其他一些变体。


如果我们希望在访问一个表时不调用 __index 元方法,那么可以使用函数 rawget 。调用 rawget(t, i) 会对表 t 进行原始的访问,即在不考虑元表的情况下对表进行简单的访问。进行一次原始访问并不会加快代码执行(一次函数调用的开销就会抹杀用户所做的这些努力),但是,我们后续会看到,有时确实会用到原始访问。

目录
相关文章
|
小程序 API
小程序踩坑记- tabBar.list[3].selectedIconPath 大小超过 40kb
小程序踩坑记- tabBar.list[3].selectedIconPath 大小超过 40kb
234 0
|
8月前
|
SQL 关系型数据库 MySQL
mysql查询语句的访问方法const、ref、ref_or_null、range、index、all
mysql查询语句的访问方法const、ref、ref_or_null、range、index、all
|
8月前
|
数据采集 前端开发 搜索推荐
HTML元信息
HTML元信息
58 1
|
8月前
|
JavaScript
js知识总结 -- Math对象、data日期对象的方法及功能
js知识总结 -- Math对象、data日期对象的方法及功能
62 0
|
Java 程序员 Go
time.After和select搭配使用时存在的”坑“
time.After和select搭配使用时存在的”坑“
173 0
ES6 —— 通过价格 / 名字查询商品(filter 和 some 的使用)
ES6 —— 通过价格 / 名字查询商品(filter 和 some 的使用)
107 0
库定义相关的元方法
库定义相关的元方法
51 0
|
SQL 关系型数据库 MySQL
MYSQL创建100万条数据与count(1)、count(*)、count(column)区别
MYSQL创建100万条数据与count(1)、count(*)、count(column)区别.md
|
C++ 容器
map以及使用举例--C++基础
map以及使用举例--C++基础
146 0
map以及使用举例--C++基础
|
算法 C++ 容器
list以及使用举例--C++基础
list以及使用举例--C++基础
125 0
list以及使用举例--C++基础