Lua Module对全局变量访问

来源:互联网 发布:linux禅道安装教程 编辑:程序博客网 时间:2024/04/30 12:13

2008年12月9日

今天下午调试程序的时候,遇到了一件非常奇怪的事。弄清楚了之后,才发现原来是Lua中Module中自有环境的问题。

大体情况是这样的,我在主程序中设定的全局变量,在模块文件中可以访问到,并修改了这个全局变量的值,但是在模块调用返回后,再次使用这个全局变量的值,发现它没有被赋值,没有被改变。究其原因,发现是因为Lua的模块里面,采用了自己的全局环境(这个全局环境会将主程序中的全局环境做为备选查找表,即使用__index联系),这与主程序中的全局环境是不一样的(两个不同的表)。模块中如果有一个变量被第一次赋值的话,Lua会认为是在模块的环境中新建一个全局变量,即使这个全局变量与主程序中的全局变量重名,它也不会去引用主程序中的全局变量,然后赋值。


下面举几一个sample来解释这种情况:

主程序文件: test.lua

require "a"
print("================================")

print(GGG[1])
print(GGG[2])

print(SKU[1])
print(SKU[2])
print("================================")

f = require "b"
f.run()

print(GGG[1])
print(GGG[2])

print(SKU[1])
print(SKU[2])
print("================================")
另一个文件: a.lua

GGG = {}
GGG[1] = 10

SKU = {}
模块文件: b.lua
module(..., package.seeall)

function run()
    print("--------------------------------")
    GGG[2] = 20

    print(GGG[1])
    print(GGG[2])

    SKU = GGG

    print(SKU[1])
    print(SKU[2])

    print("--------------------------------")
    return 0
end

运行 lua test.lua 后,结果如下:
================================
10
nil
nil
nil
================================
--------------------------------
10
20
10
20
--------------------------------
10
20
nil
nil

================================
而如果将模块文件 b.lua 改成如下形式:

module(..., package.seeall)

function run()

print("--------------------------------")
GGG[2] = 20

print(GGG[1])
print(GGG[2])

_G.SKU = GGG

print(SKU[1])
print(SKU[2])

print("--------------------------------")
return 0
end

 

那么结果如下:

================================
10
nil
nil
nil
================================
--------------------------------
10
20
10
20
--------------------------------
10
20
10
20
================================


可以看到,程序修改之前没有对主程序全局变量进行赋值,而修改之后,给主程序全局变量赋了值。


通过本例,我们还可知道,require 既可用来加载模块文件(包括动态链接库模块),也可用来加载普通的代码块文件。模块文件加载进来后,使用一个引用来调用模块中的方法和变量。而普通的代码块文件在被require调入后,就相当于(如果有Local变量,则不完全是)成了主程序代码的一部分,全局变量可以贯穿使用。(非本地)函数也可以直接调用。

Lua的如下语句:

GGG[2] = 20
实际上进行了两个操作,首先是对GGG的引用,如果在当前模块中找不到它的定义,就会通过__index元方法查找到_G中去,如果在_G中找到了,那么就引用_G中的这个GGG变量,并且给它添加一个元素值20。而如果在_G中也没有找到定义,那程序会认为是第一次碰到GGG这个变量,第一次碰到这个变量就要去引用它,并且是引用它其中的一个元素,便会报错。所以,类似这样的数据元素赋值的操作实际上是:引用加索引和赋值三个操作的结合。

而简单的赋值语句就不一样了:

SKU = GGG
这句,会引用GGG,GGG在当前模块找不到的话,会到_G中去找。它也会引用SKU,但它发现,这是这个模块中的第一次出现的变量,并且被赋值(写),于是会当成是一个新的变量来创建。因此,这里的SKU,并非_G中的那个SKU,而仅仅是模块内部的一个变量。究根揭底,还是因为模块的环境与主环境之间只有__index(读回溯),而没有__newindex(写回溯)的缘故。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xenyinzen/archive/2008/12/10/3485633.aspx

原创粉丝点击