全局变量和局部变量(local variable)

全局变量(global variable)

在Lua中定义全局变量非常简单,就是定义变量的时候,前面不要加上local。
这个神秘的全局变量,其实本质上也是一个table,它把我们创建的全局变量都保存到一个table里。
这个table的名字是:_G。

gName = "globalVar"
print(gName)        
print(_G.gName)
print(_G["gName"])
-- result:
--> globalVar
--> globalVar
--> globalVar

我们定义了一个全局变量gName,于是这个gName成为了_G的一个字段。

使用全局变量会有命名冲突和效率问题,因此我们在适用情况下往往使用局部变量。

局部变量(local variable)

局部变量只在被声明的哪个代码块内有效。
代码块:控制结构、函数、chunk(变量被声明的那个文件或者文本串)。

local fLocal = function(n)
    if (n == 1) then
        return n;
    else
        return n + fLocal(n-1)
    end
end
print("result:", fLocal(2))

会报错:attempt to call global ‘fLocal’ (a nil value)。
同样的道理,也是有两种修改方式:

  • 提前声明fLocal
    分析一下,函数fLocal中是不能识别自己的,那么编译器在到这里的时候还不能认识fLocal。这让我想起来某个语言的定义(具体是什么忘记了):只有匹配到”}”,才算定义完毕,编译器才会识别这个定义。那是什么意思呢?拿这里的local fLocal来说只有编译器解释到“end”的时候才表示fLocal定义完毕,才会有这个变量,不然都是非法的,所以解决办法就是把fLocal单独拿出来,这样编译器扫描一遍的时候就认识了,不会报错。

    local fLocal
    fLocal = function(n)
        if (n == 1) then
            return n;
        else
            return n + fLocal(n-1)
        end
    end
    print("result:", fLocal(2))
    

特例

Lua local function和function

  • 使用function声明的函数(全局函数)时,引用时不会因为声明的顺序找不到。
  • 使用local function声明的函数(局部函数)时,引用必须在函数声明后。
function test()
    test1()
    test2()
end

function test1()
    print("test1")
end

local function test2()
    print("test2")
end

test()

会报错:attempt to call global ‘test2’ (a nil value)
有两种修改方法:

  • 将local function test2的声明放到function test前面。
  • 将local function test2修改为function test2。

Lua local table和table

为什么local table比较特殊呢?首先,我们知道table的赋值与其他基本类型变量不同,是引用赋值

v1 = 1
v2 = v1 --创建了一个新的变量v2,v2的值与v1相同
v1 = nil

t1 = {
    
     v=100}
t2 = t1 --只是为t1起了一个别名t2
t1.v = nil
print(v1,v2,t1.v,t2.v)

因此要注意:避免local表引用global表

a = 1
do
local a = a --创建了一个局部变量a,赋值为全局变量a的值1
a = 2
print(a)    --2
end
print(a)    --1
t = {
    
    }
t.a = 1
do 
local t = t --这种写法是错误的,因为这里创建了一个局部表t,引用了全局表t,实际上是同一张全局表,失去了local的作用
t.a = 2
print(t.a)  --2
end
print(t.a)  --2

Note:

1.Lua 中的变量全是全局变量,无论语句块或是函数里,除非用 local 显式声明为局部变量,变量默认值均为nil。

2.使用local创建一个局部变量,与全局变量不同,局部变量只在被声明的那个代码块内有效。(代码块:指的是一个控制结构内,一个函数体,或者一个chunk(变量被声明的那个文件或者文本串))。

x = 10
local i = 1                 --local to the chunk
 
while i <= x do
    local x = i * 2           --local to the while body
    print(x)
    i = i + 1
end
 
if i > 20 then 
    local x                     -- local to the "then" body
    x = 20
    print(x + 2)
else
    print(x)
end
 
print(x)

运行结果:

2
4
6
8
10
12
14
18
20
10
10

注意:如果在交互模式下上面的例子可能不能输出如期结果,因为第二句的local i=1是一个完整的chunk,在交互模式下执行完这一句后,Lua 将开始一个新的chunk,这样第二句的i 已经超出他的有效范围。可将这段代码放在do…end中(相当于C的{…})。

3.尽可能使用局部变量,有两个好处:

  • 避免命名冲突。

  • 访问速度更快(原因是local变量是存放在lua的堆栈里面的是array操作,而全局变量是存放在_G中的table中,效率不及堆栈)。

Lua中的函数可以作为全局变量也可作为局部变量,当我们将函数保存在一个局部变量里时,我们将得到一个局部函数。局部函数和局部变量一样在一定范围内有效。

  • 使用function声明的函数为全局函数,在被引用时可以不会因为声明的顺序而找不到 。
  • 使用local function声明的函数为局部函数,在引用的时候必须要在声明的函数后面。
function test()
    test2()
    test1()
end
 
local function test1()
    print("hello test1")
end
 
function test2()
    print("hello test2")
end
 
test()

会报错:attempt to call global ‘test2’ (a nil value)
有两种修改方法:

  • 将local function test1的声明放到function test前面。
  • 将local function test1修改为function test1。

5.其他补充:

  • local变量过多也会有堆栈溢出的问题,一段过程下最多拥有200个local变量,且do end不算。类似这样:
local Class = {}
 
local test1 = 1
 
local test2 = 2
 
... --to 199
 
return Class

如果超过199,则会报出main function has more than 200 local variables的错误。当然这里说的是一段过程,所以函数是另算的,同样一个函数的过程最多也不能超过200个local变量(调用函数则算转入下一个过程了)。

  • 模块级local变量暂无限制,但是也要考虑到热更新方面的问题:若是选择使用模块级local变量去存储模块的数据,那么在热更新方面的处理将会变得十分麻烦。从这点考虑的话,模块级local变量最好只是用于引用别的模块为妙。

猜你喜欢

转载自blog.csdn.net/qq_44918090/article/details/127189274