您的位置:首页 > 编程语言 > Lua

lua 关于__index,__newindex的理解

2017-06-15 16:10 567 查看
table存在两种行为:查询和修改(赋值),我们可以通过元方法__index和__newindex来改变table的这两种行为。

__index主要用于table的查询

table[key] 的访问过程,首先检查table表中是否存在key的字段,如果有则返回,否则检查是否有__index的元方法,没有返回nil,有则查找元方法。

__index元方法可以是不一定是一个函数,还可以是一个table。如果是一个函数,则以table和不存在的key作为参数方位该函数,

例如:__index = function(t,key)

如果是一个table时,就以相同的方式来访问这个table(即传入key访问元方法的table,如果存在则放回值,反之返回nil)

例如:__index = tab --此时会返回tab[key]的值

__index可以很好的实现具有默认值的table

function setDefaultValues(t,d)
local mt = {__index = function() return d end}
setmetatable(t, mt)
end
tab = {x=10,y=20}
print(tab.x ,tab.y,tab.z) --由于没有设置元方法则为nil
setDefaultValues(tab,100) --设置默认值(设置__index元方法)
print(tab.z) --检查到有__index的元方法则返回默认值但是这种设置默认值的弊端是如果很多表都需要设置默认值,则需要创建很多元表,所以更有的做法是让元表公有,其原理类似
local mt = {__index = function(t) return t.___ end}
function setDefaultValues(t,d)
t.___= d
setmetatable(t, mt)
e__newindex主要用于table的更新

在书上用了简短一段话来描述__newindex

“当对table中不存在的索引赋值时,解释器就会查找__newindex元方法。如果有这个元方法,就调用这个元方法,而不是执行复制。如果这个元方法是一个table,解释器就在table中进行复制,而不是对原来的table。”

不得不说此处高能

1)当对table中不存在的索引赋值时,解释器就会查找__newindex元方法

这句话不难理解,顾名思义

2)如果有这个元方法,就调用这个元方法,而不是执行复制。

我们需要代码来验证这句话的含义:

local mt = {
__newindex = function (table,key,value)
print("newindex被无情地调用了")
end
}
local t = {}
setmetatable(t, mt)
t[1] = 20
for k,v in pairs(t) do
print(k ,v)
end输出结果:
newindex被无情地调用了
[Finished in 0.1s]

看的出t中不存在任何值,很多blog中有这样一段替换上面的mt():
local mt = {
__newindex = function (table,key,value)
rawset(table, key, 2)
end
}输出结果:
1	2
[Finished in 0.1s]
从以上两段代码的输出我们不难看出元表中存在__newindex方法的时候对表t某个不存在的索引的赋值,直接调用的元方法,至于具体赋什么值真的是没关系
3)如果这个元方法是一个table,解释器就在table中进行复制,而不是对原来的table。
local k = {}
local mt = {
__newindex = k
}
local t = {}
setmetatable(t, mt)
print("赋值前:")
for k,v in pairs(k) do
print(k ,v)
end
t[1] = 20
print("赋值后:t表中的值:")
for k,v in pairs(t) do
print(k ,v)
end

print("赋值后:k表中的值:")
for k,v in pairs(k) do
print(k ,v)
end

输出结果:
赋值前:
赋值后:t表中的值
赋值后:k表中的值
1	20
[Finished in 0.1s]
不难看出赋值前,k是空表,赋值后k表中输出了值 key:1 value:20 而t表依旧为空。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息