【问题标题】:In Lua, a variable is unexpectedly nil在 Lua 中,变量意外为零
【发布时间】:2013-05-29 09:16:01
【问题描述】:

我为我的《孤岛危机》服务器模组编写了一个“惩罚框”(用于惩罚违反规则的玩家),但由于某种原因,我不断收到此错误:

[警告] [Lua 错误] scripts/functions.lua:340: 尝试对全局 'tme' 执行算术运算(一个 nil 值)

但问题是,tme 实际上是一个介于 0 和 15 之间的数值。下面的代码基本上设置了“惩罚框”并检查它是否对玩家仍然有效。如您所见,tme 实际上是一个值(如果不是,则代码根本不会运行)。我在这里做错了吗?

由于这是一种特殊情况,我在互联网上找不到那么多。 tme引用自time,通过聊天命令转发给函数,肯定是数字。

另外,有没有更简单的方法?

代码:

function XPunishPlayer(Name, time, reason)
    if (time > 5) then
        System.LogAlways("[SYSTEM] Punished by administrator: "..Name:GetName().."");
    end
    if (not Msg) then
        local tme = math.floor(time*60);
        Msg = true;
        XMessageChatToPlayer(Name, "[!punish] You were punished for "..time.." minutes:    "..reason.."");
        g_gameRules.game:RenamePlayer(Name.id, "[PUNISH]"..Name:GetName().."");
        XMessageChatToPlayer(Name, "[!punish] You can use !pm to dispute this punishment.");
        g_gameRules:KillPlayer(Name);
    end
    Script.SetTimer( 1000,function()
        local tme = tme+1;
        XPunishPlayer(Name, time, reason);
        Name.actor:SetNanoSuitEnergy(0);
        local punish = math.floor(timeleft-1);
        g_gameRules.onClient:ClStepWorking(g_gameRules.game:GetChannelId(Name.id), tme);
        if (tme == math.floor(time*60)) then
            g_gameRules.onClient:ClStepWorking(g_gameRules.game:GetChannelId(Name.id), false);
            XMessageChatToPlayer(Name, "[!punish] Released from the punishbox.");
            XMessageInfoToAll("Unpunished "..Name:GetName()..", was punished for "..time.."     minutes: "..reason.." (Server Administration)");
            return;
        end
    end);
end

【问题讨论】:

  • 请正确缩进您的代码。这真的很难读。

标签: loops lua


【解决方案1】:

tme 是在 if 块中定义的,在 Lua 中每个块都会创建自己的闭包,因此 tme 的值是该块的本地值。

您可以通过简单地删除 local 关键字将其设为全局变量(这通常不是一个好主意),也可以像这样在块之前定义它:

function XPunishPlayer(Name, time, reason)
    if (time > 5) then
        System.LogAlways("[SYSTEM] Punished by administrator: "..Name:GetName().."");
    end
    local tme;
    if (not Msg) then
        tme = math.floor(time*60);
        [...]
    end
    Script.SetTimer( 1000,function()
        tme = tme-1;
        [...]
    end);
end

我也很确定您的SetTimer 中的第二个local tme 会让您再次头疼...

【讨论】:

  • Lua 中的作用域(它是 Lua,不是 LUA,顺便说一句,它不是缩写)实际上非常简单。您可能想阅读它in the manual hereespecially here。不过,正确的缩进有很大帮助;)
  • 一致缩进帮助的方法之一是使基本块的范围清晰,这将使局部变量的范围也清晰。简而言之,local 的范围从它被声明的点到包含该声明的块的末尾(有一个特殊的怪癖,允许repeat local done=true until done 做它明显意味着的事情)。没有缩进就很难发现这种错误。
  • 吹毛求疵:每个块都定义了一个范围,而不是一个闭包。当然,闭包是一个块,因此也是一个范围。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-02
  • 2016-06-26
  • 2012-12-14
  • 1970-01-01
  • 2017-01-20
  • 2018-01-02
  • 1970-01-01
相关资源
最近更新 更多