脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Lua - Lua中的__index和__newindex实例

Lua中的__index和__newindex实例

2020-04-14 10:45果冻想 Lua

这篇文章主要介绍了Lua中的__index和__newindex实例,本文讲解了具有默认值的table、记录table的访问、只读的table等内容,需要的朋友可以参考下

前言

这篇博文将通过几个简单的实例演示,巩固对__index和__newindex的理解,同时加深对Lua中元表和元方法的理解,如果对Lua的元表和元方法还不是很熟悉的话,请参考这篇文章:《Lua中的元表与元方法》。

具有默认值的table

我们都知道,table中的任何字段的默认值都是nil,但是通过元表,我们可以很容易的修改这一规定,代码如下:

 

复制代码 代码如下:

function setDefault(tb, defaultValue)
     local mt = {__index = function () return defaultValue end}
     setmetatable(tb, mt)
end
 
local tb1 = {x = 10, y = 20}
print(tb1.x, tb1.z)     --> 10 nil
setDefault(tb1, 100) -->设置默认值
print(tb1.x, tb1.z) --> 10 100 这里打印的就是默认值


可以看到,在代码中,setDefault函数为所有需要默认值的table创建了一个新的元表。如果准备创建很多需要默认值得table,这种方法的开销或许就比较大了。由于在元表中默认值defaultValue是与元方法关联在一起的,所以setDefault无法为所有table都使用同一个元表。如果要让具有不同默认值得table都使用同一个元表,那么就需要将每个元表的默认值存放在table本身中,可以使用一个额外的字段来存储默认值。例如以下代码:

 

 

复制代码 代码如下:

local mt = {__index = function (t) return t.___ end}
function setDefault(tb, defaultValue)
     tb.___ = defaultValue       -- 非常谢谢hellowei犀利的review。具体请参见评论
     setmetatable(tb, mt)
end


上面代码中的“___”是为了防止名字冲突而起的名字;如果这样的话,你还担心名字冲突,确保key在table中的唯一性,只需要创建一个新的table,并用它作为key即可,每一个新创建的table都是一个唯一的地址,比如以下代码:

 

 

复制代码 代码如下:

local key = {} -- 唯一的key
local mt = {__index = function (tb) return tb[key] end}
 
function setDefault(tb, defaultValue)
     tb[key] = defaultValue
     setmetatable(tb, mt)
end

 

记录table的访问

有的时候,一种特定的需求,我们需要记录对一个table的所有访问,不管是查询还是更新,我们都需要记录日志。这如何完成?我们都知道,元表中的__index和__newindex是在table中没有所需要访问的index时才发挥作用的,因此,只有将一个table保持为空,然后设置__index和__newindex元方法,才有可能记录下来所有对它的访问。

为了监视一个table的所有访问,就应该为真正的table创建一个代理。这个代理就是一个空的table,其中__index和__newindex元方法可用于跟踪所有的访问,并将访问重定义到原来的table上。这就是思路,接下来看代码:

 

复制代码 代码如下:

local t = {} --原来的table
 
-- 保持对原table的一个引用
local _t = t
 
-- 创建代理
t = {}
 
-- 创建元表
local mt = {
__index = function (t, k)
print("access to element " .. tostring(k))
return _t[k]
end,
 
__newindex = function (t, k, v)
print("update of element " .. tostring(k))
_t[k] = v
end
}
 
setmetatable(t, mt)
 
t.x = 10 -- update of element x
print(t.x) -- access to element x


如果想要同时监视几个table,无须为每个table创建不同的元表;相反,只要以某种形式将每个代理与其原table关联起来,并且所有代理都共享一个公共的元表。这个问题与设置table默认值相关联的问题类似,也是将原来的table保存在代理table的一个特殊的字段中。代码如下:

 

 

复制代码 代码如下:

-- 创建唯一索引
local index = {}
 
-- 创建元表
local mt = {
     __index = function (t, k)
          print("access to element " .. tostring(k))
          return t[index][k]
     end,
 
     __newindex = function (t, k, v)
          print("update of element " .. tostring(k))
          t[index][k] = v
     end
}
 
function track(t)
     local proxy = {}
     proxy[index] = t
     setmetatable(proxy, mt)
     return proxy
end
 
local t = {}
local proxy = track(t)
proxy.x = 10
print(proxy.x)

 

只读的table

通过代理的概念,可以很容易的实现只读的table。只需要跟踪所有对table的更新操作,并引发一个错误就好了,对于查询时,我们不用去馆,只需要管对table的更新操作,废话不说,来段简单的代码,自然而然的一目了然了。

复制代码 代码如下:

function readOnly(t)
     local proxy = {}
 
     -- 创建元表
     local mt = {
          __index = t,
          __newindex = function (t, k, v)
               error("Attempt to update a read-only table", 2)
          end
     }
 
     setmetatable(proxy, mt)
     return proxy
end
 
local tbDemo = readOnly{1, 2, 3, 4, 5}
print(tbDemo[1])
tbDemo[1] = 20


元表中__index对应的是原来的table,而更新原来的table时,就会显示错误提示:Attempt to update a read-only table。

 

总结

这篇文章对Lua中的__index和__newindex的使用进行了详细的讲解和分析,并提供了实际的代码,主要是为了加深对Lua中元表和元方法的理解,元表和元方法在Lua中的地位太总要了,很多高级的编程技巧和特殊需求都是基于元表和元方法来实现了,所以,也希望大家能好好的阅读这篇文章,同时也希望我的文章对大家有帮助。

延伸 · 阅读

精彩推荐
  • LuaC语言中调用Lua函数实例

    C语言中调用Lua函数实例

    这篇文章主要介绍了C语言中调用Lua函数实例,本文讲解了调用一个Lua函数的步骤和C语言调用Lua函数实例,需要的朋友可以参考下 ...

    脚本之家9262020-04-27
  • LuaLua中的控制结构(流程控制)简明总结

    Lua中的控制结构(流程控制)简明总结

    这篇文章主要介绍了Lua中的控制结构(流程控制)简明总结,本文讲解了IF、repeat、while、for、break、return等语句,需要的朋友可以参考下 ...

    脚本之家3522020-04-14
  • LuaLua中调用C++函数示例

    Lua中调用C++函数示例

    这篇文章主要介绍了Lua中调用C++函数示例,本文给出的C++函数average()演示了如何接受多个参数且返回超过一个值,需要的朋友可以参考下 ...

    脚本之家3642020-05-06
  • LuaLua学习笔记之数据类型

    Lua学习笔记之数据类型

    这篇文章主要介绍了Lua学习笔记之数据类型,本文同时讲解了开发环境的搭建,需要的朋友可以参考下 ...

    皂荚花4382019-11-17
  • LuaLua中的函数相关知识点整理汇总

    Lua中的函数相关知识点整理汇总

    这篇文章主要介绍了Lua中的函数相关知识点整理汇总,包括函数的参数传递和定义函数等基本知识,需要的朋友可以参考下 ...

    脚本之家2562020-05-03
  • LuaLua中写排序算法实例(选择排序算法)

    Lua中写排序算法实例(选择排序算法)

    这篇文章主要介绍了Lua中写排序算法实例,本文用一个选择排序算法为例讲解如何在Lua中写一个排序算法,需要的朋友可以参考下 ...

    脚本之家7902020-04-27
  • LuaLua教程(八):数据持久化

    Lua教程(八):数据持久化

    这篇文章主要介绍了Lua教程(八):数据持久化,本文讲解了数据文件持久化、序列化两部份内容,需要的朋友可以参考下 ...

    Lua教程网5292020-04-29
  • LuaLua中遍历数组和table的4种方法

    Lua中遍历数组和table的4种方法

    这篇文章主要介绍了Lua中遍历数组和table的4种方法,本文讲解了使用for遍历、迭代器的方式遍历等方法,同时提供一个复杂table的的遍历方法,需要的朋友可以...

    脚本之家23952020-04-26