Lua 在不丢失引用的情况下重新初始化表
我希望在不丢失对表的引用的情况下重新初始化表 我想要实现的是在文件中定义表,当文件被更改(使用文本编辑器)时,会重新加载文件,从而更改表。当然,这不会更改表,但会创建一个新实例,旧引用仍将指向旧表 有什么建议吗 编辑:我想详细说明我想要实现的目标。一个游戏人物和武器的例子。我想修改arms.lua,从而影响角色Lua 在不丢失引用的情况下重新初始化表,lua,Lua,我希望在不丢失对表的引用的情况下重新初始化表 我想要实现的是在文件中定义表,当文件被更改(使用文本编辑器)时,会重新加载文件,从而更改表。当然,这不会更改表,但会创建一个新实例,旧引用仍将指向旧表 有什么建议吗 编辑:我想详细说明我想要实现的目标。一个游戏人物和武器的例子。我想修改arms.lua,从而影响角色 -- weapons.lua sword = { damage = 3 } -- characters.lua character = { weapon = sword } 像JWT
-- weapons.lua
sword = { damage = 3 }
-- characters.lua
character = { weapon = sword }
像JWT建议的那样添加一个间接级别(将“剑”放在“武器”中)没有帮助,除非我将角色拆分为{weaponTable=weapons,weapontkey=“swark”},但我不认为这是一个选项。您可以将这些表嵌套在另一个表中 之前:
local a = { 1, 2, 3 }
local b = { 7, 8, 9 }
print(a[2] + b[2]) -- #=> 10
之后:
local lookup = {
a = { 1, 2, 3 },
b = { 7, 8, 9 }
}
print(lookup.a[2] + lookup.b[2]) -- #=> 10
然后,您可以完全替换(或仅更新)查找表中的一个表,任何依赖语句都将使用该更新值:
lookup.a = { 100, 50, 0 }
print(lookup.a[2] + lookup.b[2]) -- #=> 58
您可以将这些表嵌套在另一个表中 之前:
local a = { 1, 2, 3 }
local b = { 7, 8, 9 }
print(a[2] + b[2]) -- #=> 10
之后:
local lookup = {
a = { 1, 2, 3 },
b = { 7, 8, 9 }
}
print(lookup.a[2] + lookup.b[2]) -- #=> 10
然后,您可以完全替换(或仅更新)查找表中的一个表,任何依赖语句都将使用该更新值:
lookup.a = { 100, 50, 0 }
print(lookup.a[2] + lookup.b[2]) -- #=> 58
我不知道这是否正是你所需要的(因为身份证是必要的),但我希望它能满足你的需要
meta = {
tables = {},
__call = function(arg, t)
for k, v in pairs(t) do
arg[k] = v
end
end,
__bnot = function(arg)
return arg.__key
end,
__newindex = function(arg, key, val)
meta.tables[arg.__key][key] = val
end,
__index = function(arg, key)
return meta.tables[arg.__key][key]
end
}
function RefTable(arg)
local newtable = {}
if arg ~= nil then
newtable.__key = arg
setmetatable(newtable, meta)
if meta.tables[arg] == nil then
meta.tables[arg] = {}
end
else
error("RefTable can't have nil key")
end
return newtable
end
-- Using the RefTable
sword = RefTable("Sword")
sword({damage = 3})
sword.cooldown = 10
character = {sword = sword}
print("base", sword.damage, sword.cooldown)
print("embed", character.sword.damage, character.sword.cooldown)
sword = RefTable("Sword")
sword({damage = 8, cooldown = 50})
print("embed2", character.sword.damage, character.sword.cooldown)
print(sword.__key, sword.cooldown)
ref = RefTable("Sword")
ref.cooldown = 1000
print(sword.cooldown)
我不知道这是否正是你所需要的(因为身份证是必要的),但我希望它能满足你的需要
meta = {
tables = {},
__call = function(arg, t)
for k, v in pairs(t) do
arg[k] = v
end
end,
__bnot = function(arg)
return arg.__key
end,
__newindex = function(arg, key, val)
meta.tables[arg.__key][key] = val
end,
__index = function(arg, key)
return meta.tables[arg.__key][key]
end
}
function RefTable(arg)
local newtable = {}
if arg ~= nil then
newtable.__key = arg
setmetatable(newtable, meta)
if meta.tables[arg] == nil then
meta.tables[arg] = {}
end
else
error("RefTable can't have nil key")
end
return newtable
end
-- Using the RefTable
sword = RefTable("Sword")
sword({damage = 3})
sword.cooldown = 10
character = {sword = sword}
print("base", sword.damage, sword.cooldown)
print("embed", character.sword.damage, character.sword.cooldown)
sword = RefTable("Sword")
sword({damage = 8, cooldown = 50})
print("embed2", character.sword.damage, character.sword.cooldown)
print(sword.__key, sword.cooldown)
ref = RefTable("Sword")
ref.cooldown = 1000
print(sword.cooldown)
锚定在全球环境中生存所需的一切。嵌套很好,并且这不一定是您的主要参考。(您仍然可以local
操作,但请确保从全局环境中初始化这些局部变量,并在更改局部变量时更新全局变量。)
要初始化全局值,请执行以下操作:
foo = foo or value -- if foo is always true-ish
bar = (bar == nil) and value or bar -- if bar may be `false`
要初始化或更新表,可以
foo = foo or { }
foo.bar = foo.bar or 23
foo.baz = foo.baz or 42
-- and so on...
但这有点恶心,所以你可以说
function reinit( new, old ) -- (re)initialize one level, prefer old
if old == nil then return new end
if type( old ) ~= "table" then return old end
for k, v in pairs( new ) do
if old[k] == nil then old[k] = v end
end
return old
end
function reset( new, old ) -- (re)initialize one level, prefer new
if old == nil then return new end
if type( old ) ~= "table" then return new end
for k, v in pairs( new ) do old[k] = v end
return old
end
然后就
foo = reinit( { bar = 23, baz = 42 }, foo ) -- only setting if not defined
-- or
foo = reset( { bar = 23, baz = 42 }, foo ) -- always overriding given fields
或者让它更别致,说
function traverse( t, path )
local here, last, lastk, created = t
-- follow path of several keys starting from t, creating tables as needed
for k in path:gmatch "[^.]+" do
k = tonumber( k ) or k -- convert all-number keys to integer (for arrays)
local next = here[k]
if not next then
next, created = { }, true
here[k] = next
else
created = false
end
lastk, last, here = k, here, next
end
return here, last, lastk, created
end
function repopulate( path, value, update )
update = update or reinit -- pass 'reset' as 'update' for the other behavior
-- or something entirely different if that's what you need
local here, last, lastk, created = traverse( _G, path )
if type( value ) == "table" then
update( value, here )
else
if created then last[lastk] = nil end -- created one level too much
update( { [lastk] = value }, last )
end
end
然后(使用任意嵌套)
你可以更进一步,添加元方法来隐藏一些混乱,定义不同的更新策略您已经看到了一些可能性,现在开始构建适合您的风格和代码的自己的版本
(尽管您可以自由地以任何方式使用上述代码,但请注意,它是在浏览器中临时编写的。我做了一些测试,修复了一些故障,现在似乎可以正常工作,但如果仍然有一两个bug隐藏在其中,请不要感到惊讶。因此,请使用它,更改它,将其破坏(并查看它如何/为什么会破坏),修改并扩展它,…–但除非您完全理解它的功能并能够修复任何错误,否则我强烈建议您编写自己的版本,或者只坚持基本原则。您可能不需要这项功能的所有功能,而且您可能需要这项功能无法完成的其他功能。因为这是重新加载/实时编码的核心部分nfrastructure和所有东西都必须进行调整以实现重新加载兼容,您的工具和实际需要之间的任何不匹配都会在代码中的任何地方造成很大的痛苦。因此,如果您需要类似的东西,请花一两天时间使其按您需要的方式工作,否则您会后悔的。)
(免费奖金警告:如果你做OOP,你可能不得不存储和检索你的类,而不是每次都创建它们,否则以前迭代中的旧对象将错过代码更新,仍然运行它们的旧方法。我已经忘记了这一点,而不仅仅是几次,浪费了几个小时思考“为什么现在还没有修复?!?”在反复重新加载代码之后…记住锚定元表,锚定类!)锚定在全局环境中生存所需的所有内容。嵌套很好,这不一定是您的主要参考。(您仍然可以
local
操作,但请确保从全局环境中初始化这些局部变量,并在更改局部变量时更新全局变量。)
要初始化全局值,请执行以下操作:
foo = foo or value -- if foo is always true-ish
bar = (bar == nil) and value or bar -- if bar may be `false`
要初始化或更新表,可以
foo = foo or { }
foo.bar = foo.bar or 23
foo.baz = foo.baz or 42
-- and so on...
但这有点恶心,所以你可以说
function reinit( new, old ) -- (re)initialize one level, prefer old
if old == nil then return new end
if type( old ) ~= "table" then return old end
for k, v in pairs( new ) do
if old[k] == nil then old[k] = v end
end
return old
end
function reset( new, old ) -- (re)initialize one level, prefer new
if old == nil then return new end
if type( old ) ~= "table" then return new end
for k, v in pairs( new ) do old[k] = v end
return old
end
然后就
foo = reinit( { bar = 23, baz = 42 }, foo ) -- only setting if not defined
-- or
foo = reset( { bar = 23, baz = 42 }, foo ) -- always overriding given fields
或者让它更别致,说
function traverse( t, path )
local here, last, lastk, created = t
-- follow path of several keys starting from t, creating tables as needed
for k in path:gmatch "[^.]+" do
k = tonumber( k ) or k -- convert all-number keys to integer (for arrays)
local next = here[k]
if not next then
next, created = { }, true
here[k] = next
else
created = false
end
lastk, last, here = k, here, next
end
return here, last, lastk, created
end
function repopulate( path, value, update )
update = update or reinit -- pass 'reset' as 'update' for the other behavior
-- or something entirely different if that's what you need
local here, last, lastk, created = traverse( _G, path )
if type( value ) == "table" then
update( value, here )
else
if created then last[lastk] = nil end -- created one level too much
update( { [lastk] = value }, last )
end
end
然后(使用任意嵌套)
您还可以更进一步,添加元方法来隐藏一些混乱,定义不同的更新策略,…–您已经看到了一些可能性,现在开始构建适合您的风格和代码的自己的版本
(尽管您可以自由地以任何方式使用上述代码,但请注意,它是在浏览器中临时编写的。我做了一些测试,修复了一些故障,现在似乎可以正常工作,但如果仍然有一两个bug隐藏在其中,请不要感到惊讶。因此,请使用它,更改它,将其破坏(并查看它如何/为什么会破坏),修改并扩展它,…–但除非您完全理解它的功能并能够修复任何错误,否则我强烈建议您编写自己的版本,或者只坚持基本原则。您可能不需要这项功能的所有功能,而且您可能需要这项功能无法完成的其他功能。因为这是重新加载/实时编码的核心部分nfrastructure和所有东西都必须进行调整以实现重新加载兼容,您的工具和实际需要之间的任何不匹配都会在代码中的任何地方造成很大的痛苦。因此,如果您需要类似的东西,请花一两天时间使其按您需要的方式工作,否则您会后悔的。)
(免费奖金警告:如果你使用OOP,你可能必须存储和检索你的类,而不是每次都创建它们,否则以前迭代中的旧对象将错过代码更新,仍然运行它们的旧方法。我已经忘记了这一点,而不仅仅是几次,浪费了几个小时思考”为什么现在还没有修复?!“在反复重新加载代码之后……请记住锚定元表,锚定类!)这有确切的