require加载模块

Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行,Lua提供了一个名为require的函数用来加载模块。要加载一个模块,只需要简单地调用就可以了,执行以下语句 require 会返回一个由模块常量或函数组成的 table,并且还会定义一个包含该 table 的全局变量。

require("module")--nodule.lua文件

这里先将加载过程中涉及到的package想关信息说明下
package.path
这个路径被 require 在 Lua 加载器中做搜索时用到。
在启动时,Lua 用环境变量 LUA_PATH_5_3 或环境变量 LUA_PATH 来初始化这个变量。 或采用 luaconf.h 中的默认路径。 环境变量中出现的所有 "; ; "都会被替换成默认路径
package.cpath
这个路径被 require 在 C 加载器中做搜索时用到。
Lua 用和初始化 Lua 路径 package.path 相同的方式初始化 C 路径 package.cpath 。 它会使用环境变量 LUA_CPATH_5_3 或 环境变量 LUA_CPATH 初始化。要么就采用 luaconf.h 中定义的默认路径。
package.loaded
用于 require 控制哪些模块已经被加载的表。 当你请求一个 modname 模块,且 package.loaded[modname] 不为假时, require 简单返回储存在内的值。这个变量仅仅是对真正那张表的引用; 改变这个值并不会改变 require 使用的表。
package.loadlib (libname, funcname)
让宿主程序动态链接 C 库 libname 。
当 funcname 为 "*", 它仅仅连接该库,让库中的符号都导出给其它动态链接库使用。 否则,它查找库中的函数 funcname ,
以 C 函数的形式返回这个函数。 因此,funcname 必须遵循原型 lua_CFunction (参见 lua_CFunction)。
这是一个低阶函数。 它完全绕过了包模块系统。 和 require 不同, 它不会做任何路径查询,也不会自动加扩展名。 libname 必须是一个 C库需要的完整的文件名,如果有必要,需要提供路径和扩展名。 funcname 必须是 C 库需要的准确名字 (这取决于使用的 C 编译器和链接器)。这个函数在标准 C 中不支持。 因此,它只在部分平台有效 ( Windows ,Linux ,Mac OS X, Solaris, BSD, 加上支持 dlfcn 标准的 Unix 系统)。
package.preload
保存有一些特殊模块的加载器 (参见 require)。
这个变量仅仅是对真正那张表的引用; 改变这个值并不会改变 require 使用的表。
package.searchers
用于 require 控制如何加载模块的表。
这张表内的每一项都是一个 查找器函数。 当查找一个模块时, require 按次序调用这些查找器, 并传入模块名(require 的参数)作为唯一的一个参数。 此函数可以返回另一个函数(模块的 加载器)加上另一个将传递给这个加载器的参数。 或是返回一个描述为何没有找到这个模块的字符串 (或是返回 nil 什么也不想说)。
Lua 用四个查找器函数初始化这张表。
第一个查找器就是简单的在 package.preload 表中查找加载器。
第二个查找器用于查找 Lua 库的加载库。 它使用储存在 package.path 中的路径来做查找工作。 查找过程和函数 package.searchpath 描述的一致。
第三个查找器用于查找 C 库的加载库。 它使用储存在 package.cpath 中的路径来做查找工作。 同样, 查找过程和函数 package.searchpath 描述的一致。 例如,如果 C 路径是这样一个字符串
"./?.so; ./?.dll; /usr/local/?/init.so"
查找器查找模块 foo 会依次尝试打开文件 ./foo.so,./foo.dll, 以及 /usr/local/foo/init.so。 一旦它找到一个 C 库, 查找器首先使用动态链接机制连接该库。 然后尝试在该库中找到可以用作加载器的 C 函数。 这个 C 函数的名字是 "luaopen_" 紧接模块名的字符串, 其中字符串中所有的下划线都会被替换成点。 此外,如果模块名中有横线, 横线后面的部分(包括横线)都被去掉。 例如,如果模块名为 a.b.c-v2.1, 函数名就是 luaopen_a_b_c。
第四个搜索器是 一体化加载器。 它从 C 路径中查找指定模块的根名字。 例如,当请求 a.b.c 时, 它将查找 a 这个 C 库。 如果找得到,它会在里面找子模块的加载函数。 在我们的例子中,就是找 luaopen_a_b_c。 利用这个机制,可以把若干 C 子模块打包进单个库。 每个子模块都可以有原本的加载函数名。
除了第一个(预加载)搜索器外,每个搜索器都会返回 它找到的模块的文件名。 这和 package.searchpath 的返回值一样。 第一个搜索器没有返回值。
package.searchpath (name, path [, sep [, rep]])
在指定 path 中搜索指定的 name 。
路径是一个包含有一系列以分号分割的 模板 构成的字符串。 对于每个模板,都会用 name 替换其中的每个问号(如果有的话)。 且将其中的 sep (默认是点)替换为 rep (默认是系统的目录分割符)。 然后尝试打开这个文件名。
例如,如果路径是字符串
"./?.lua; ./?.lc; /usr/local/?/init.lua"
搜索 foo.a 这个名字将 依次尝试打开文件 ./foo/a.lua , ./foo/a.lc ,以及 /usr/local/foo/a/init.lua。
返回第一个可以用读模式打开(并马上关闭该文件)的文件的名字。 如果不存在这样的文件,返回 nil 加上错误消息。 (这条错误消息列出了所有尝试打开的文件名。)
【require加载模块】
一般我们加载一个模块的步骤如下:
1、加载一个模块。 require函数首先查找package.loaded表, 检测modname是否被加载过。 如果被加载过,require返回 package.loaded[modname]中保存的值
否则,它试着为模块寻找加载器 。
2、lua的加载器存储在package的searchers表中,共有四个加载器,require也按照顺序来执行加载器。找到了就成功返回,没有就继续查找。首选查找预加载器,执行package.preload[modname],如果这里有值,这个值(必须是一个函数)就是那个加载器, 否则 require 使用 Lua 加载器去查找package.path 的路径。 如果查找失败,接着使用C加载器去查找package.cpath的路径。如果都失败了,再尝试一体化加载器(参见 package.searchers)
每次找到一个加载器,require 都用两个参数调用加载器: modname 和一个在获取加载器过程中得到的参数。(如果通过查找文件得到的加载器,这个额外参数是文件名。) 如果加载器返回非空值, require 将这个值赋给 package.loaded[modname]。 如果加载器没能返回一个非空值用于赋给 package.loaded[modname], require 会在那里设入 true 。 无论是什么情况,require 都会返回 package.loaded[modname] 的最终值。
如果在加载或运行模块时有错误, 或是无法为模块找到加载器, require 都会抛出错误。

参考:http://www.runoob.com/manual/lua53doc/manual.html#pdf-string.format

    推荐阅读