Lua是如何找到之前已被赋值的特定局部变量的正确值的?

由于全局变量存储在名为_ENV的表中,它们可以通过表中的名称作为键来找到。

Lua如何找到之前已被赋值的特定局部变量的正确值?

编辑:

这是演示代码:

do
    local a=1;
    local b=2;
    local c=3;

    sum = a+c;
end

Lua如何知道变量a的值是1?

点赞
用户7746452
用户7746452

根据LUA参考文献

除非明确声明为本地变量,否则任何变量名称都被视为全局变量(参见第3.3.7节)。本地变量在词法上是作用域区分的:本地变量可以被在其作用域内定义的函数自由访问(参见第3.5节)。

所以:

function printA()
  print(a)
end

a = 1
print(a) -- 1
local a = 2
print(a) -- 2
do
  print(a) -- 2
  local a = 3
  print(a) -- 3
end
print(a) -- 2
printA() -- 1
2020-12-31 10:54:03
用户11740758
用户11740758

通常在 do ... end 或者 function(...) ... end 中定义的局部变量和函数才有意义。例如在我的安卓 QLua 上,在没有遵守以上规则时不会打印任何东西,仅仅是 nil

Lua 5.2.3  Copyright (C) 1994-2013 Lua.org, PUC-Rio
> local a=1
> local b=2
> print(a,b)
nil     nil
> do local a=1 local b=2 print(a,b) end
1       2
2020-12-31 12:13:10
用户12110258
用户12110258

和其它解释型语言一样,Lua 运行在一个「栈」上方,字面意义就是这个样子。这个高大的存储结构存放 Lua 脚本的所有内存。(术语「堆栈溢出」就是指这个堆栈耗尽了所有内存)

在 Lua 编译期间,Lua 寻找本地变量,并在堆栈上为它们分配空间:

local a = "abc" -- 项目 #1
local b = "abc" -- 项目 #2
local c = "abc" -- 项目 #3

当你运行这个脚本时,Lua 的内存看起来就像这样:

+-------+
| "abc" |
+-------+
| "abc" |
+-------+
| "abc" |
+-------+

当你进入 do end 作用域(或任何作用域)时,这也是词汇作用域,Lua 会在堆栈上创建一个新区域,词汇作用域结束时丢弃该区域。

local a = "abc"
do
    local b = "xyz"
end

应该看起来像这样:

之前:    在 "do" 中:   之后:
+-------+  +-------+  +-------+
| "abc" |  | "abc" |  | "abc" |
+-------+  +-------+  +-------+
           +-------+
           | "xyz" |
           +-------+

有趣的是,Lua 没有「全局变量」。每个变量都在堆栈上,只是一个简单的表查找。

这是通过 upvalue 实现的;Lua 作用域可以访问上面作用域的本地变量。但是,当你在 load 中加载一个全新的 Lua 块(函数),它没有 upvalue。为了实现全局变量,所有块都有一个 upvalue,_ENV。所有「全局」变量实际上只是该表上的一个索引。

由于 _ENV 始终位于堆栈底部,所以 Lua 轻松查找全局变量。 (但它的速度较慢)

+------+
| _ENV |
+------+
+-------+
| "abc" |
+-------+

最后一个例子:

local a = "abc" -- 项目 #1
b = "xyz" -- _G["b"] = "xyz"
c = b -- _G["c"] = _G["b"]
local z = "awesome" -- 项目 #2

澄清一下:所有操作都在 Lua 堆栈上进行。当你想调用一个函数 - 添加两个数字,甚至查找一个表时,所有这些操作都在 Lua 堆栈上执行。如果你对这个如何工作感兴趣,请查阅 Lua C API。

2020-12-31 23:21:57