初学者,有错误希望指正。
19——————————————————————————————环境变量
--声明全局变量,防止拼写错误引起的bug
--将说有全局变量保存在一个表中,使用metttables改变访问全局变量的行为
#!/usr/local/bin/lua
local declaredNames = {}
function declare (name, initval)
rawset(_G, name, initval)
--rawset绕过metatable
declaredNames[name] = true
end
setmetatable(_G, {
__newindex = function (t, n, v)
if not declaredNames[n] then
error("attempt to write to undeclared var. "..n, 2)
else
rawset(t, n, v)
end
end,
__index = function (_, n)
if not declaredNames[n] then
error("attempt to read undeclared var. "..n, 2)
else
return nil
end
end,
})
declare("a",1)
print(a)
--非全局变量
--使用setfenv在一段chunk中改变环境
--使用继承封装新的环境
a=1
local newgt={}
setmetatable(newgt,{__index=_G})
setfenv(1,newgt)
print(a)
--任何操作对新表进行
20————————————————————packages包
--像标准库,使用表来描述package--module.lua文件
--[[
local module={}
function module.one(...)
--body
end
function module.two(...)
--body
end
......
,....
--私有成员(privacy)
local function three(...)
--body
end
--优点:package中所有名字在一个独立的命名空间,每一个实体(entity)都清楚的标记为公有还是私有。
--私有实体在package外部不可访问
--缺点:公有实体加上前缀module
--修改函数状态,必须修改函数调用方式
return module
]]
--解决上方chunk的优缺点
--所有函数声明为局部
local function one(...) end
local function two(...) end
local function three(...) end
local function four(...) end
local function five(...) end
module={
one=one,
two=two,
three=three,
four=four,
}
--在module中列出所有的公有函数
return module
--基本格式:用表封装函数
--使用时 用 require "module"调用
--require命令使用文件问不是packages,不需要固定的扩展名,由路径设置决定
————————————————————————————————————————————
--使用全局变量表的metamethods实现package
--package使用独占的环境,
--改变pacjage主chunk的环境,创建的所有函数都共享这个新的环境
local p={}
module=p
setfenv(1,p)
function one(...)
--body
end
--这样设置后,one会自动变成module.one,内部的声明或者调用都不需要前缀
————————————————————————————————————————————————————
--主package中定义一个辅助表来记录函数存放的位置:
local location = {
foo = "/usr/local/lua/lib/pack1_1.lua",
goo = "/usr/local/lua/lib/pack1_1.lua",
foo1 = "/usr/local/lua/lib/pack1_2.lua",
goo1 = "/usr/local/lua/lib/pack1_3.lua",
}
--创建package并定义metamethod:
pack1 = {}
setmetatable(pack1, {__index = function (t, funcname)
local file = location[funcname]
if not file then
error("package pack1 does not define " .. funcname)
end
assert(loadfile(file))()
return t[funcname]
end})
return pack1
--加载这个package之后,第一次程序执行pack1.foo()将触发__index metamethod,接着发现函数有一个相应的文件,并加载这个文件。微妙之处在于:加载了文件,同时返回函数作为访问的结果。
--因为整个系统都使用Lua写的,所以很容易改变系统的行为。
--例如,函数可以是用C写的,在metamethod中用loadlib加载他。
--或者我们我们可以在全局表中设定一个metamethod来自动加载整个packages.