Indexing lua索引一个nil值

Indexing lua索引一个nil值,indexing,lua,null,Indexing,Lua,Null,到目前为止,我一直在用谷歌搜索这个问题,但没有结果,所以我想知道是否有人知道答案-当你在lua中索引一个nil值时,脚本会引发一个错误-尝试索引'variableName'-一个nil值-是否可以用一个可能是元方法的方法来捕获它,进行一些处理而不出错?例如,如果未定义变量'num',您说'num=2',您可以设置_newindex metamethod进行一些处理,并且堆栈上有变量名-'num'和值-'2',但是如果您说'num[2]=3',并且没有定义'num',您会出错,就像_newinde

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

您可以覆盖全局表上的_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
global的这一特定用法,并以某种方式从中恢复过来吗?你提供的环境越多,其他人就越容易找到你可能没有想到的解决方案

至于您所描述的情况,如果您想要捕获
num[index]
num
nil
,您实际上无法直接检测到

这有两个部分:

  • 从当前环境表(aka _ENV或_G)中读取
    num的当前值时
  • 当您尝试索引该值时
  • 无法检测#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
    

    您将得到“尝试索引为零!”并且程序将继续运行。

    问题并不完全清楚。你是说num是一个表变量吗?或者num只是脚本的一个局部变量?它既不是,也不是,“num”还没有定义-但是您尝试以任何方式对它进行索引,而不是引发错误,我希望使用未定义的变量名“num”、索引和值,以便我可以进行一些处理,就像使用uuu newindexI一样,我想我还不够清楚:如果我重写uu newindex metamethod语句,比如:num=15,其中num是一个未声明的变量,将被捕获,您可以同时使用字符串'num'和值15来执行操作。但是像:num[2]=15这样的语句,其中num是未声明的,不管我们是否覆盖了_newindex,都会导致错误。错误是:“尝试索引'num'-一个nil值”是的,我认为没有一种方法可以让您在不将赋值包装在pcall()中并尝试从错误中恢复的情况下“捕获”您试图捕获的内容。想想你在做什么。您正在尝试捕捉G表的_索引,创建一个新表,捕捉该_索引,并为其赋值。我真的不知道你会怎么做,实际上你应该在尝试索引它之前先显式地创建num。这是非常标准的编程原则。我会在周一回来的时候试一试,然后再发回更多的评论。