背景
为了实现上篇最后所讲的创建新table的方法,需要解决如下几个问题:
- 如何支持设置原table中的值为nil
- 如何支持使用pairs遍历新table
代理表
支持设置原table中的值为nil的方案,首先得引入一个另外的方案 table代理的支持这个table代理能够让每次访问代理的调用都通过代理上的元表,实现如下:
function createNewTable(parent)
local values = {} -- 用来存放新的值
-- 代理表,每次通过这个表访问和赋值都会经过下面元表的__index和__newindex方法
-- 新的值会存储到values表中,访问的时候先从values表中查找,如果没有找到,在去parent中查找
local proxy =
setmetatable(
{},
{
__index = function(__, k)
local retValue = values[k]
if retValue ~= nil then
return retValue
end
return parent[k]
end,
__newindex = function(__, k, v)
values[k] = v
end
}
)
return proxy
end
local tbA = {a = 1}
local tbB = createNewTable(tbA)
tbB.b = 2
print(tbB.a) -- 1
print(tbB.b) -- 2
tbB.a = 3
tbB.b = 4
print(tbB.a) -- 3
print(tbB.b) -- 4
tbB.a = nil
tbB.b = nil
print(tbB.a) -- 1
print(tbB.b) -- nil
支持赋值为nil
从代理表的实现以及测试结果来看,代理表本身也是无法实现赋值原table中存在的数值为nil的。所以在此基础上还需要引入专门的存储哪些字段为nil的table,实现如下:
function createNewTable(parent)
local values = {} -- 用来存放新的值
local nils = {} -- 存放空值
-- 代理表,每次通过这个表访问和赋值都会经过下面元表的__index和__newindex方法
-- 新的值会存储到values表中,访问的时候先从values表中查找,如果没有找到,在去parent中查找
local proxy =
setmetatable(
{},
{
__index = function(__, k)
if nils[k] then -- 只要存在于nils中,直接返回nil
return nil
end
local retValue = values[k]
if retValue ~= nil then
return retValue
end
return parent[k]
end,
__newindex = function(__, k, v)
if v == nil then -- 如果v为nil,设置nils表中的k为true, 并且设置 values表中的k为nil
nils[k] = true
values[k] = nil
else
values[k] = v
end
end
}
)
return proxy
end
local tbA = {a = 1}
local tbB = createNewTable(tbA)
tbB.b = 2
print(tbB.a) -- 1
print(tbB.b) -- 2
tbB.a = 3
tbB.b = 4
print(tbB.a) -- 3
print(tbB.b) -- 4
tbB.a = nil
tbB.b = nil
print(tbB.a) -- nil
print(tbB.b) -- nil
如此,便实现了设置原table中存在的值为nil的需求,但是依然不支持遍历
预告
所以在下一篇中会实现,遍历这样的一张表