在C++中,在包含头文件之后,还需要使用命名空间。
头文件中是库函数,命名空间是为了区分不同的库,以防两个库有相同的函数名称。
而lua中也有类似的机制,package
package是记录在另一个文件中,里面存放了要用的库函数,当需要用到这个库函数的时候,只要加载它就可以。
由于package之间也有可能存在同名的全局变量,如果不做处理,很有可能会出现未知的错误。
在前面的一小节,提到了环境,将一个chunk的环境修改之后,后续代码声明的全局变量将统一记录在环境的表里,而不是记录在全局变量。利用这一点,进行对package进行改造。
代码如下:
local q = {}
Set = q
setmetatable(q,{__index = _G})
local _ENV = q
mt = {}
function New(t)
local set = {}
setmetatable(set,mt)
for _,i in ipairs(t) do set[i] = true end
return set
end
function union(a,b)
local res = New{}
for k in pairs(a) do res[k] = true end
for k in pairs(b) do res[k] = true end
return res
end
function intersection(a,b)
local res = New{}
for k in pairs(a) do
res[k] = b[k]
end
return res
end
function eq(a,b)
for k in pairs(a) do
if not (b[k]) then return false end
end
return true
end
function le(a,b)
for k in pairs(a) do
if not(b[k]) then return false end
end
return true
end
function lt(a,b)
return a <= b and not(b <= a)
end
function tostring(set)
local s = "{"
local sep = ""
for k in pairs(set) do
s = s..sep..k
sep = ", "
end
s = s.."}"
return s
end
function print(set)
print(tostring(set))
end
mt.__eq = eq
mt.__le = le
mt.__lt = lt
mt.__add = union
mt.__mul = intersection
mt.__tostring = tostring
return Set
上述代码是单独存放到一个叫做Set.lua的文件中。
在package的开头,声明了一个局部变量p,然后将它赋值给package的名称,package是全局的。
之后将全局变量的_G表作为非全局环境的metatable的__index的值,最后将环境设置为p。
现在在Set.lua文件中声明的所有全局变量都会登记到p中,而不会影响全局变量。
最后,将package的名称返回,这句代码可有可无,一般都会写上。
现在用另一个测试的lua文件调用它
function test()
require"Set"
s1 = Set.New{1,2,3,4,5}
s2 = Set.New{2,3,4,5,7,8}
s = s1 <= s2
print(s)
end
do
test()
for k in pairs(_G) do
print(k)
end
end
在test函数的开头,加载了Set,就可以直接可以使用Set中的函数了。
打印了一下全局变量的表,其中只多了一个Set,而不会把package中非全局环境中声明的全局变量当作全局变量。
另外这一小节还对文件和package的关系做了阐述,也提供了一种防止两个package同名导致加载的时候产生混乱。这种技术好像不能用了,在这个链接里有解释,https://stackoverflow.com/questions/2869829/requiredname-always-nil