到目前为止,我一直在谷歌搜索这个问题无济于事,所以我想知道是否有人知道答案 - 当你在 lua 中索引一个 nil 值时,脚本会引发一个错误 - 尝试索引“variableName” - 一个 nil 值 - 是吗有可能用可能是元方法来捕获它,做一些处理而不是出错吗?例如,如果变量 'num' 没有定义并且你说 'num = 2' 你可以设置 __newindex 元方法来做一些处理并且你有变量名 - 'num' 和值 - '2' 在堆栈上,但是如果你说 'num[2] = 3' 并且 'num' 没有定义你会出错 - 就像 __newindex 一样,我想捕获该事件并访问 nil 变量的名称 - 'num', index - 2,设置值 - 3。任何帮助将不胜感激。
2 回答
您可以覆盖全局表上的 __newindex 元方法。
function OnNewIndex(tbl, key, value)
if tbl[key] == nil then
print(tostring(key).. " doesn't exist.")
end
end
setmetatable(_G, { __newindex = OnNewIndex })
num = 15
但是,默认情况下,我不相信 lua 有这种行为。只是做类似的事情:
num = 15
应该只将变量“num”声明为全局变量并将值 15 分配给它。您是否将 lua 用作某些对此进行严格检查的框架的一部分?
编辑:在不让它冒泡的情况下“捕捉”这个错误的一种简单方法是将赋值包装在这样的 pcall 中......
pcall(function() num[2] = 15 end)
如果你打印这个,你会得到输出:
false test2.lua:18: attempt to index global 'num' (a nil value)
这至少给了你一些关于发生了什么的迹象,如果你命名了这个函数,我猜你可能会尝试恢复。
function TrySetValue()
num[2] = 15
end
local result, msg = pcall(TrySetValue)
if (not result) then
num = {}
end
result, msg = pcall(TrySetValue)
print(result, msg)
print(num[2])
当您可能只是预先修复代码时,这似乎是一项非常艰巨的工作。
首先,如果您陈述您要解决的问题,则更容易提供帮助。您是否试图防止使用未初始化的全局变量?您可以使用元表来做到这一点。您是否试图确保脚本错误永远不会渗透到您的应用程序中?你可以用pcall
. 您真的只是想抓住nil
全局的这一特定用法,并以某种方式从中恢复吗?您提供的上下文越多,其他人就越容易找到您可能没有想到的解决方案。
至于你描述的情况,你想捕捉num[index]
where num
is nil
,你并不能真正直接检测到。
这有两个部分:
num
从当前环境表(又名 _ENV 或 _G)中读取的当前值时- 当您尝试索引该值时。
您无法检测到#2,因为nil
它不是表,所以您不能给它一个元表。
但是,您可以检测到 #1。根据您的要求,您可以使用 #1 返回一个代理对象,然后该对象将允许您检测 #2,但这意味着永远不会有全局nil
,因此这样的逻辑将不起作用:
--- initialize globalFoo if it doesn't exists
if not globalFoo then
globalFoo = CreateGlobalFoo()
....
当然,你总是可以做一些事情,比如命名你的代理对象NIL
,所以你可以写:
if globalFoo == NIL then -- globalFoo is not initilalize
globalFoo = CreateGlobalFoo()
像这样工作的代理对象的示例:
local nil_proxy_mt = {
__index = function(t,k) print('Attempted to index nil!') end,
__newindex = function(t,k,v) print('Attempted to index nil!') end,
}
local NIL = setmetatable({}, nil_proxy_mt)
setmetatable (_G, { __index = function(t,k) return NIL end })
有了这个,如果你尝试了以下任何一个:
foo = num[2]
num[2] = 15
你会得到“尝试索引零!” 并且程序继续运行。