Lua变量的作用域是什么?

3

我很想知道这段代码为什么可以工作,并打印相同的表格。

t = {

    f = function()
        return t
    end

}

print(t)
print(t.f())

我曾认为 t 只有在定义之后才能被访问,因此 return t 应该会失败。但是这段代码似乎与此相矛盾。

1个回答

4
由于在您的示例中没有本地变量“t”,因此您的函数访问全局t(即:_ENV.t)。当调用函数时,它访问_ENV变量的当前值,然后索引该_ENV值的"t"索引。尽管在定义函数时_ENV表不包含t,但在稍后调用它时,它确实包含t,因此您可以访问新定义的表。
local u = {
    f = function()
        -- Refers to the global variable `t` (that is, _ENV.t).
        -- Whenever the function is called, the *current* value of `t` is returned
        return t 
    end
}

print(u) -- prints table: 0xFOOBAR
print(u.f()) -- prints nil

t = u

print(t) --prints table: 0xFOOBAR
print(t.f()) --prints table: 0xFOOBAR

_ENV = {print = print}
print(u.f()) -- prints nil, since _ENV.t is now nil

local _ENV = {print = print, t = u}
print(u.f()) -- still prints nil, because the function definition used the
             -- _ENV variable that was lexically visible at the function definition,
             -- rather than the new _ENV variable that was just defined.

使用_ENV的意思是这些示例仅适用于Lua 5.2,但同样的原则也适用于Lua 5.1。


谢谢!很清楚你的代码做了我期望做的事情。我的问题是,我真正想了解的是为什么t可以访问,即使它还没有被创建。 - oroszgy
1
@oroszgy:函数定义中的t指的是全局变量t,其值可以在后续阶段更改。在赋值之前,全局变量的值为nil,赋值后变量保存了表格。您在赋值之后调用函数,因此该值是从函数返回的值。 - Mankarse
@oroszgy:Lua具有词法作用域。绑定的变量正是最内部可见的变量(如果没有局部变量可见,则为全局变量)。每当使用该变量时,都会使用当前值,而不是该变量在首次引用时存在的值(例如,在函数定义运行时首次引用该变量)。 - Mankarse
@oroszgy:我从示例中移除了local t。相反,我展示了在t重新赋值之前调用f的示例。重点是每当调用f时,都使用当前_ENV值。 - Mankarse
感谢@Mankarse!对我来说关键点是当t.f()被调用时,f的主体才会被解释。 - oroszgy
@oroszgy,“解释性”在这里可能会被误解。在任何执行之前,整个源代码都会被编译。函数定义被编译为始终返回特定变量t的值。Lua是“词法作用域”。因此,在您的代码中没有其他t在作用域内,特定变量是全局环境的t字段。 - Tom Blodget

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接