1

到目前为止,我一直在谷歌搜索这个问题无济于事,所以我想知道是否有人知道答案 - 当你在 lua 中索引一个 nil 值时,脚本会引发一个错误 - 尝试索引“variableName” - 一个 nil 值 - 是吗有可能用可能是元方法来捕获它,做一些处理而不是出错吗?例如,如果变量 'num' 没有定义并且你说 'num = 2' 你可以设置 __newindex 元方法来做一些处理并且你有变量名 - 'num' 和值 - '2' 在堆栈上,但是如果你说 'num[2] = 3' 并且 'num' 没有定义你会出错 - 就像 __newindex 一样,我想捕获该事件并访问 nil 变量的名称 - 'num', index - 2,设置值 - 3。任何帮助将不胜感激。

4

2 回答 2

1

您可以覆盖全局表上的 __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])

当您可能只是预先修复代码时,这似乎是一项非常艰巨的工作。

于 2012-08-03T15:50:16.443 回答
1

首先,如果您陈述您要解决的问题,则更容易提供帮助。您是否试图防止使用未初始化的全局变量?您可以使用元表来做到这一点。您是否试图确保脚本错误永远不会渗透到您的应用程序中?你可以用pcall. 您真的只是想抓住nil全局的这一特定用法,并以某种方式从中恢复吗?您提供的上下文越多,其他人就越容易找到您可能没有想到的解决方案。

至于你描述的情况,你想捕捉num[index]where numis nil,你并不能真正直接检测到。

这有两个部分:

  1. num从当前环境表(又名 _ENV 或 _G)中读取的当前值时
  2. 当您尝试索引该值时。

您无法检测到#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

你会得到“尝试索引零!” 并且程序继续运行。

于 2012-08-03T17:18:36.020 回答