Lua table 具有默认值和自动 table 创建
Lua tables with defaults and automatic table creation
我需要一些关于 Lua metatable 的帮助,特别是 AutomagicTables (http://lua-users.org/wiki/AutomagicTables)。只分配给未定义的 tables 的能力非常好,我想保留这个功能。我的版本已经放在单函数中:
require("dataentry") -- Contains my age function
function AutomagicTable()
-- Create a new data table
-- from https://lua-users.org/wiki/AutomagicTables
local auto, assign
function auto(tab, key)
return setmetatable({}, {
__index = auto,
__newindex = assign,
parent = tab,
key = key
})
end
local meta = {__index = auto}
function assign(tab, key, val)
if val ~= nil then
local oldmt = getmetatable(tab)
oldmt.parent[oldmt.key] = tab
setmetatable(tab, meta)
tab[key] = val
else
return nil
end
end
return setmetatable({}, meta)
end
我想要的是传递 table 个默认值,以便在未定义字段时使用 - 如 PIL 第 13 章 (https://www.lua.org/pil/13.4.3.html) 中所述。这将允许在我的数据结构中计算和查找字段。以下是我要使用的语法:
t_defaults = {
Age = age(table["DOB"]),
Sex = "Female",
}
t = AutomagicTable(t_defaults)
t.ID12345.DOB = "7/2/1965"
t.ID12346.DOB = "1/2/1945"
print("ID12345",t.ID12345.Sex,t.ID12345.DOB,t.ID12345.Age)
print("ID12346",t.ID12346.Sex,t.ID12346.DOB,t.ID12346.Age)
请注意,此代码 age() 中对当前 table(见下文)的 DOB 字段的引用失败,因为 table["DOB"] 为零。如果您 运行 此代码没有默认值,Automagic returns 一个 table 用于缺失值。
我可以按照 PIL 第 13 章中的示例分配默认值,但是语法很乱,一旦应用我就失去了 AutomagicTable 功能(因为我分配了不同的元table):
-- Make a metatables
t_defaults = {}
t_defaults.__index = function (table, key)
local def = {
Age = age(table["DOB"]),
Sex = "Female"
}
return def[key]
end
-- Set new metatable - but now we can't make anymore Automagic tables
setmetatable(t.ID12345, t_defaults)
setmetatable(t.ID12346, t_defaults)
-- This will work
print("ID12345",t.ID12345.Sex,t.ID12345.DOB,t.ID12345.Age)
print("ID12346",t.ID12346.Sex,t.ID12346.DOB,t.ID12346.Age)
-- This assignment fails
t.ID12347.DOB = "12/12/1945"
不幸的是,我不完全理解 AutomagicTables 代码,并且正在努力在 AutomagicTable 代码中添加所需的功能。
感谢收到的任何帮助。
加文
我认为你在这里不需要全面的自动魔法。
仅应自动创建用户(即深度级别为 1 的对象)。
因此,可以使用更简单的逻辑:
local function age(DOB_str)
local m, d, y = (DOB_str or ""):match"^(%d+)/(%d+)/(%d+)$"
if m then
local t = {month = tonumber(m), day = tonumber(d), year = tonumber(y)}
local now = os.date"*t"
local now_year = now.year
now = os.time{year = now_year, month = now.month, day = now.day}
local lower_bound = math.max(0, now_year - t.year - 1)
local completed_years = -1 + lower_bound
t.year = t.year + lower_bound
repeat
completed_years = completed_years + 1
t.year = t.year + 1
until os.difftime(now, os.time(t)) < 0
return completed_years
end
end
-- Class "User"
local user_default_fields = {Sex = "Female"}
local user_mt = {__index =
function (tab, key)
if key == "Age" then -- this field is calculatable
return age(tab.DOB)
else -- other fields are constants
return user_default_fields[key]
end
end
}
-- The table containing all users with auto-creation
local users = setmetatable({}, {__index =
function (tab, key)
local new_user = setmetatable({}, user_mt)
tab[key] = new_user
return new_user
end
})
-- usage
users.ID12345.DOB = "12/31/1965"
users.ID12346.DOB = "1/2/1945"
print("ID12345", users.ID12345.Sex, users.ID12345.DOB, users.ID12345.Age)
print("ID12346", users.ID12346.Sex, users.ID12346.DOB, users.ID12346.Age)
我需要一些关于 Lua metatable 的帮助,特别是 AutomagicTables (http://lua-users.org/wiki/AutomagicTables)。只分配给未定义的 tables 的能力非常好,我想保留这个功能。我的版本已经放在单函数中:
require("dataentry") -- Contains my age function
function AutomagicTable()
-- Create a new data table
-- from https://lua-users.org/wiki/AutomagicTables
local auto, assign
function auto(tab, key)
return setmetatable({}, {
__index = auto,
__newindex = assign,
parent = tab,
key = key
})
end
local meta = {__index = auto}
function assign(tab, key, val)
if val ~= nil then
local oldmt = getmetatable(tab)
oldmt.parent[oldmt.key] = tab
setmetatable(tab, meta)
tab[key] = val
else
return nil
end
end
return setmetatable({}, meta)
end
我想要的是传递 table 个默认值,以便在未定义字段时使用 - 如 PIL 第 13 章 (https://www.lua.org/pil/13.4.3.html) 中所述。这将允许在我的数据结构中计算和查找字段。以下是我要使用的语法:
t_defaults = {
Age = age(table["DOB"]),
Sex = "Female",
}
t = AutomagicTable(t_defaults)
t.ID12345.DOB = "7/2/1965"
t.ID12346.DOB = "1/2/1945"
print("ID12345",t.ID12345.Sex,t.ID12345.DOB,t.ID12345.Age)
print("ID12346",t.ID12346.Sex,t.ID12346.DOB,t.ID12346.Age)
请注意,此代码 age() 中对当前 table(见下文)的 DOB 字段的引用失败,因为 table["DOB"] 为零。如果您 运行 此代码没有默认值,Automagic returns 一个 table 用于缺失值。
我可以按照 PIL 第 13 章中的示例分配默认值,但是语法很乱,一旦应用我就失去了 AutomagicTable 功能(因为我分配了不同的元table):
-- Make a metatables
t_defaults = {}
t_defaults.__index = function (table, key)
local def = {
Age = age(table["DOB"]),
Sex = "Female"
}
return def[key]
end
-- Set new metatable - but now we can't make anymore Automagic tables
setmetatable(t.ID12345, t_defaults)
setmetatable(t.ID12346, t_defaults)
-- This will work
print("ID12345",t.ID12345.Sex,t.ID12345.DOB,t.ID12345.Age)
print("ID12346",t.ID12346.Sex,t.ID12346.DOB,t.ID12346.Age)
-- This assignment fails
t.ID12347.DOB = "12/12/1945"
不幸的是,我不完全理解 AutomagicTables 代码,并且正在努力在 AutomagicTable 代码中添加所需的功能。
感谢收到的任何帮助。
加文
我认为你在这里不需要全面的自动魔法。
仅应自动创建用户(即深度级别为 1 的对象)。
因此,可以使用更简单的逻辑:
local function age(DOB_str)
local m, d, y = (DOB_str or ""):match"^(%d+)/(%d+)/(%d+)$"
if m then
local t = {month = tonumber(m), day = tonumber(d), year = tonumber(y)}
local now = os.date"*t"
local now_year = now.year
now = os.time{year = now_year, month = now.month, day = now.day}
local lower_bound = math.max(0, now_year - t.year - 1)
local completed_years = -1 + lower_bound
t.year = t.year + lower_bound
repeat
completed_years = completed_years + 1
t.year = t.year + 1
until os.difftime(now, os.time(t)) < 0
return completed_years
end
end
-- Class "User"
local user_default_fields = {Sex = "Female"}
local user_mt = {__index =
function (tab, key)
if key == "Age" then -- this field is calculatable
return age(tab.DOB)
else -- other fields are constants
return user_default_fields[key]
end
end
}
-- The table containing all users with auto-creation
local users = setmetatable({}, {__index =
function (tab, key)
local new_user = setmetatable({}, user_mt)
tab[key] = new_user
return new_user
end
})
-- usage
users.ID12345.DOB = "12/31/1965"
users.ID12346.DOB = "1/2/1945"
print("ID12345", users.ID12345.Sex, users.ID12345.DOB, users.ID12345.Age)
print("ID12346", users.ID12346.Sex, users.ID12346.DOB, users.ID12346.Age)