【Lua】模块与包
定义:
从用户观点来看,一个模块就是一个程序库,可以通过require来加载(require用于使用模块,module用于创建模块),然后便得到了一个全局变量,表示一个table,这个table就像一个名字空间,其内容就是模块中导出的所有东西,例如函数和变量。一个规范的模块还应使require返回这个table
require函数:
require实现如下:
说明:
table package.loaded检查模块是否已经加载,如果加载require返回相应的值,只要一个模块已加载,后续的require调用都会返回同一个值,不会再次加载。
如果模块未加载,require会尝试为该模块找到一个加载器(loader,代码中一抽象函数findloader表示),会现在table package.preload 中查询传入的模块名,如果在其中找到了一个函数,就以该函数作为模块的加载器。
如果require为指定的模块找到了一个Lua文件,它就通过loadfile加载文件,如果找到的是一个C程序库,就通过loadlib加载,loadfile和loadlib都只是加载代码,并没有运行他们,require将返回值存储到table package.loaded中,以此作为将来对同一模块调用的返回值,如果加载器没有返回值,require就会返回table package.loaded 中的值。
注意,上述代码中在调用加载器前,require将true赋给package.loaded相应字段,以此将模块标记为已加载。这是因为如果一个模块要求加载另一个模块,而后者有递归的加载前者,那么后者的require调用会马上返回,从而避免无限循环。
若要强制使require对同一个库加载两次,可以删除package.loaded中的模块,再次加载该模块:
require路径:
require采用的路径是一连串的模式,其中每项都是一种将模块名转换为文件名的方式,路径中每项都是一个文件名,每项中还包含一个可选的问号。require会以模块名来代替每个“?”然后根据替换结果检查是否存在这样一个文件,如果不存在,就会尝试下一项,路径中每项以分号隔开,require用于搜索Lua文件的路径存放在变量package.path中,如果require无法找到模块名相符的Lua文件,它就会找C程序库,输出package.path 和package.cpath分别如下:
调用 require("sql")时,将分别尝试打开如下文件:
.\sql.lua
D:\Lua\5.1\lua\sql.lua
.......
module函数:
默认情况下module不提供外部访问。 module函数,其对应的功能实现如下:
module不提供外部访问,必须在调用它前,为需要访问的外部函数或者模块声明适当的局部变量,也可以通过继承实现外部访问,只需在调用module时加上一个选项,package.seeall,这个选项等价于以下代码:
因此,只需要如下使用:
子模块与包:
Lua支持具有层级性的模块名,可以用一个点来分隔名称中的层级。假如,一个模块名为mod.sub,那么它就是mod的一个子模块,在搜索一个定义子模块的文件时,require会将点转换为另一个字符,通常就是系统的目录分隔符(UNIX上为"/",Windows上为"\")