在 Lua 中,将未定义的标识符分配给未声明的变量是什么意思?

发布于 2024-09-27 22:18:42 字数 875 浏览 8 评论 0原文

我正在仔细阅读 Lua 代码文件,文件的最顶部包含:

    1  | TradeSkillFrameReset = TradeSkillFrame_LoadUI;
    2  | 
    3  | TradeSkillFrame_LoadUI = function()
    4  |    TradeSkillFrameReset();
            ...
    112|    TradeSkillFrame_LoadUI = TradeSkillFrameReset;
            ...
    114| end;

他们正在执行分配的第一行:

TradeSkillFrameReset = TradeSkillFrame_LoadUI;

此时在代码文件中,他们正在分配一个未声明的标识符 (TradeSkillFrame_LoadUI)未声明的变量 (TradeSkillFrameReset)。 Lua 允许这样做吗?

  • 变量声明是隐式的吗?
  • 所有未声明的标识符都被假定为前向声明吗?

更令人困惑的是,第一个 TradeSkillFrame_LoadUI 似乎是调用自身:

TradeSkillFrame_LoadUI = function()
   TradeSkillFrameReset();

这怎么不是一个无限循环?


编辑:添加了对 TradeSkillFrameResetTradeSkillFrame_LoadUI 的剩余引用。

I was perusing an Lua code file, and the very top of the file contains:

    1  | TradeSkillFrameReset = TradeSkillFrame_LoadUI;
    2  | 
    3  | TradeSkillFrame_LoadUI = function()
    4  |    TradeSkillFrameReset();
            ...
    112|    TradeSkillFrame_LoadUI = TradeSkillFrameReset;
            ...
    114| end;

The very first line they are doing an assignment:

TradeSkillFrameReset = TradeSkillFrame_LoadUI;

At this point in the code file they are assigning an undeclaraed identifier (TradeSkillFrame_LoadUI) to an undeclared variable (TradeSkillFrameReset). Is this allowed in Lua?

  • is variable declaration implicit?
  • are all undeclared identifiers assumed to be forward declarations?

The more confusing thing is that the first TradeSkillFrame_LoadUI seems to do is call itself:

TradeSkillFrame_LoadUI = function()
   TradeSkillFrameReset();

How is this not an infinite loop?


Edit: Added remaining references to TradeSkillFrameReset and TradeSkillFrame_LoadUI.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

梦巷 2024-10-04 22:18:42

如果 TradeSkillFrame_LoadUI 是全局函数,则第一条语句会在 TradeSkillFrameReset 中捕获此函数。

然后,对 TradeSkillFrame_LoadUI 的分配会将全局函数替换为新函数,该函数首先通过 TradeSkillFrameReset 引用调用原始函数。

这种模式被称为“函数挂钩”,这里是一些关于通用技术和一些魔兽世界的更多信息Lua 环境特定详细信息(根据函数名称,该脚本可能来自何处)

一些示例代码,以明确这一点:

function SomeGlobalFunction()
    print("I'm the original global function")
end

OrigFunction = SomeGlobalFunction

SomeGlobalFunction = function()
    OrigFunction()
    print("And here's the modfied one...")
end

--...
SomeGlobalFunction()

这将打印以下输出:

我是原来的全局函数

这是修改后的...

顺便说一下,Lua 的名字是 并非全部大写

If TradeSkillFrame_LoadUI is a global function, the first statement captures this function in TradeSkillFrameReset.

The assigment to TradeSkillFrame_LoadUI then replaces the global function with a new one, that at first calls the original function through the TradeSkillFrameReset reference.

This pattern is called "function hooking", here is some more information about the general technique and some World of Warcraft Lua environment specific details (where this script may come from, according to the function's name)

Some example code, to make this clear:

function SomeGlobalFunction()
    print("I'm the original global function")
end

OrigFunction = SomeGlobalFunction

SomeGlobalFunction = function()
    OrigFunction()
    print("And here's the modfied one...")
end

--...
SomeGlobalFunction()

this will print the following output:

I'm the original global function

And here's the modfied one...

As a side note, Lua's name is not all capitalized.

神爱温柔 2024-10-04 22:18:42

在第一行,由于 TradeSkillFrame_LoadUI 是一个未初始化的变量,因此第一行:

TradeSkillFrameReset = TradeSkillFrame_LoadUI;

与以下代码相同:

TradeSkillFrameReset = nil

下面的函数不会进入无限循环,因为 TradeSkillFrameReset 实际上不是 '指向那里的任何东西。

我的猜测是,稍后在代码中,它会被正确初始化。就像这样:

TradeSkillFrameReset = TradeSkillFrame_LoadUI;

TradeSkillFrame_LoadUI = function()  -- 1. function declaration
   TradeSkillFrameReset();

   [...snip...]
end;

[... snip ...]
TradeSkillFrameReset = somethingElse -- 2. initialized to something else
TradeSkillFrame_LoadUI()             -- 3. function invocation

技巧是你可以在 1 上定义一个函数,并在 3 上使用变量的值,同时在 2 上更改它。

如果这还不够清楚,请告诉我。

On the first line, since TradeSkillFrame_LoadUI is a non-initialized variable, then this first line:

TradeSkillFrameReset = TradeSkillFrame_LoadUI;

Is the same as making:

TradeSkillFrameReset = nil

The function below that doesn't enter an infinite loop because TradeSkillFrameReset isn't actually 'pointing to anything' there.

My guess is that later on in the code, it gets properly initialized. Like so:

TradeSkillFrameReset = TradeSkillFrame_LoadUI;

TradeSkillFrame_LoadUI = function()  -- 1. function declaration
   TradeSkillFrameReset();

   [...snip...]
end;

[... snip ...]
TradeSkillFrameReset = somethingElse -- 2. initialized to something else
TradeSkillFrame_LoadUI()             -- 3. function invocation

The trick is that you can define a function on 1, and use the value of a variable on 3, while changing it on 2.

Let me know if this is not clear enough.

任谁 2024-10-04 22:18:42

除非您正在使用的环境中全局变量的行为已被修改,否则该语句绝对不会执行任何操作。

local TradeSkillFrameReset = TradeSkillFrame_LoadUI

会产生效果,创建一个局部变量“槽”并使代码超过该点使用局部变量槽进行 TradeSkillFrameReset,而不是对其进行全局变量查找。然而,正如您发布的代码中一样,它只是将全局变量分配给 nil,这具有擦除它的效果,换句话说,如果它已经是 nil 则没有效果。

可能存在的原因:

1) 完成全局变量赋值后,代码运行的环境会执行一些特殊操作,而不是简单赋值的默认行为。但我认为这不太可能,就好像有任何特殊行为一样,查找 nil TradeSkillFrame_LoadUI 可能会导致错误。

2)最可能的原因只是为了可读性。它是为了让您知道 TradeSkillFrameReset被正确分配到稍后埋藏在代码中的某个地方,您不会轻易注意到它。

Unless the behavior of global variables has been modified in the environment that you're using has been modified, the statement does absolutely nothing.

local TradeSkillFrameReset = TradeSkillFrame_LoadUI

Would have an effect, creating a local variable "slot" and making code past that point use the local variable slot for TradeSkillFrameReset rather than doing a global variable lookup for it. However, as it is in the code you posted, it simply assigns the global variable to nil, which has the effect of erasing it, in other words, no effect if it was already nil.

Reasons it could be there:

1) The environment the code is running in does something special when a global variable assignment is done, rather than the default behavior of a simple assignment. I don't think this is likely though, as if there was any special behavior the lookup of the nil TradeSkillFrame_LoadUI would probably cause an error.

2) The most probable reason is simply for readability. It's to let you know that TradeSkillFrameReset will be properly assigned to later buried somewhere in the code where you won't notice it as readily.

神回复 2024-10-04 22:18:42

最重要的是,Lua 代码可以轻松地将全局变量注入到其他 Lua 代码中。我使用过很多 Lua,他们使用环境来添加全局变量。仅仅因为 var 没有在该文件中定义,并不意味着它不存在。它甚至不必在另一个文件中定义为全局变量,因为您可以以编程方式注入环境表,就像它是任何其他表一样。

The main thing to take away is that it's easy for Lua code to inject global variables into other Lua code. I've used a lot of Lua where they use the environment to add global vars. Just because a var isn't defined in that file most assuredly does not mean that it does not exist. It doesn't even have to be defined as a global variable in another file, because you can inject into the environment table programmatically as if it were any other table.

晚风撩人 2024-10-04 22:18:42

我猜它的作用类似于 Javascript 的函数提升,你可以在这里阅读:在声明之前引用 JavaScript 值 - 有人可以解释一下吗

I would guess its doing something similar to Javascript's function hoisting, which you can read about here: Referencing a JavaScript value before it is declared - can someone explain this

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文