模块与包
使用require加载模块
一个规范的模块应该返回一个table作为这个模块所有导出功能的集合
lua里没通过任何强制性语法规则要求创建模块时反回一个table
但最好这么做,因为大多lua的模块都是这么发布的
--require的实现源代码
function require(name)
if not package.loaded[name] then
local loader = findloader(name)
if loader == nil then
error("unable to load module "..name)
end
package.loaded[name] = true
local res = loader(name)
if res ~= nil then
package.loaded[name] = res
end
end
return package.loaded[name]
end
require的内部实现就是通过loadfile或loadlib来加载程序块
所以加载模块就当相于把程序块看做一个函数
然后使用模块的文件名作参数调用一次就加载完成了
只要使用require加载过一次的模块就不会再重复加载了,除非手动把package.loaded[name]=nil
已加载的模块记录在package.loaded的table里
loader是一个加载器,它会从package.preload里找对应的加载函数来实施加载
require"mod"会得到一个全局的mod变量
local m = require"mod"可以重定义导入模块的名称
require的加载路径如:
?;?.lua;c:\windows\?;/usr/local/lua/?/?.lua
require会以模块名来替换所有"?",每个条目用";"隔开
也就是说require只处理分号和问号
require用于搜索lua文件的路径存放在变量package.path中
当lua启动后便以环境变量LUA_PATH来初始化这个变量
如果没有找到环境变量LUA_PATH就以编译时定义的一个默认常是值来初始化
LUA_PATH里的";;"子串会替换成默认路径
如果require找不到lua文件就会去找c程序库,路径放在package.cpath里用LUA_CPATH初始化
在加载c程序库里如果模块名如a-b,则以b为模块加载
如果一个模块名为mod.sub则认为sub是mod的子模块,在require时会使用配置好的分隔符替换"."
如果mod.sub会替换为mod\sub这样就可以很容易的分目录放置了
使用module创建模块
手工写法
--创建模块-------------------------------------------------------------------------------- --require会把文件名当参数传进来,用这个变量记下来就行了
local modname = ...
--创建一个local的table用于记录导出内容
local _M = {}
--导出的table就等于这个local的table
_G[modname] = _M
--有了这句就不用return _G[modname]给require了
package.loaded[modname] = _M
--设置本环境继承全局环境,不然连接print都不能用,
--其实如果在模块中要用全局内容,可能赋给local变量然后使用
setmatetable(_M, {__index = _G})
--把这个local的table调成当前环境
setfenv(1, _M)
--模块内容 ------------------------------------------------------------------------------ --由于使用了环境,所以local根本就不会进入环境,也就不会导出了
local function test001()
print("test001")
end
--全局函数相当于_M.test002=function()end会导出
function test002()
print("test002")
end
内建module关键字
--这一句把上面创建模块部分的代码都包括了,没有package.seeall就不继承全局环境
module(...,package.seeall)