lua中module和require解析

前言编程

从Lua5.1版本开始,就对模块和包添加了新的支持,可以使用require和module来定义和使用模块和包。require用于使用模块,module用于建立模块。简单的说,一个模块就是一个程序库,能够经过require来加载。而后便获得了一个全局变量,表示一个table。这个table就像是一个命名空间,其内容就是模块中导出的全部东西,好比函数和常量,一个符合规范的模块还应使require返回这个table。windows

require函数数组

Lua提供了一个名为require的函数用来加载模块。要加载一个模块,只须要简单地调用require “<模块名>”就能够了。这个调用会返回一个由模块函数组成的table,而且还会定义一个包含该table的全局变量。可是,这些行为都是由模块完成的,而非require。因此,有些模块会选择返回其它值,或者具备其它的效果。那么require究竟是如何加载模块的呢?函数

首先,要加载一个模块,就必须的知道这个模块在哪里。知道了这个模块在哪里之后,才能进行正确的加载。当咱们写下require “mod”这样的代码之后,Lua是如何找这个mod的呢?ui

在搜索一个文件时,在windows上,不少都是根据windows的环境变量path来搜索,而require所使用的路径与传统的路径不一样,require采用的路径是一连串的模式,其中每项都是一种将模块名转换为文件名的方式。require会用模块名来替换每一个“?”,而后根据替换的结果来检查是否存在这样一个文件,若是不存在,就会尝试下一项。路径中的每一项都是以分号隔开,好比路径为如下字符串:
代码以下:lua

 ?;?.lua;c:\windows\?;/usr/local/lua/?/?.lua

那么,当咱们require “mod”时,就会尝试着打开如下文件:spa

mod
mod.lua
c:\windows\mod
/usr/local/lua/mod/mod.lua

能够看到,require函数只处理了分号和问好,其它的都是由路径本身定义的。在实际编程中,require用于搜索的Lua文件的路径存放在变量package.path中,在个人电脑上,print(package.path)会输出如下内容:code

 ;.\?.lua;C:\Program Files (x86)\Lua\5.1\lua\?.lua;C:\Program Files (x86)\Lua\5.1\lua\?\init.lua;C:\Program Files (x86)\Lua\5.1\?.lua;C:\Program Files (x86)\Lua\5.1\?\init.lua;C:\Program Files (x86)\Lua\5.1\lua\?.luac;.\?.lua;C:\Program Files (x86)\Lua\5.1\lua\?.lua;C:\Program Files (x86)\Lua\5.1\lua\?\init.lua;C:\Program Files (x86)\Lua\5.1\?.lua;C:\Program Files (x86)\Lua\5.1\?\init.lua;;D:\Game\5.1\lua\?.luac

若是require没法找到与模块名相符的Lua文件,那Lua就会开始找C程序库;这个的搜索地址为package.cpath对应的地址,在个人电脑上,print(package.cpath)会输出如下值:字符串

 .\?.dll;.\?51.dll;C:\Program Files (x86)\Lua\5.1\?.dll;C:\Program Files (x86)\Lua\5.1\?51.dll;C:\Program Files (x86)\Lua\5.1\clibs\?.dll;C:\Program Files (x86)\Lua\5.1\clibs\?51.dll;C:\Program Files (x86)\Lua\5.1\loadall.dll;C:\Program Files (x86)\Lua\5.1\clibs\loadall.dll

当找到了这个文件之后,若是这个文件是一个Lua文件,它就经过loadfile来加载该文件;若是找到的是一个C程序库,就经过loadlib来加载。loadfile和loadlib都只是加载了代码,并无运行它们,为了运行代码,require会以模块名做为参数来调用这些代码。it

若是lua文件和C程序库都找不到,怎么办?咱们试一下,随便require一个东西,好比:

 require "demo"
 no field package.preload['demo']
 no file '.\demo.lua'
 no file 'C:\Program Files (x86)\Lua\5.1\lua\demo.lua'
 no file 'C:\Program Files (x86)\Lua\5.1\lua\demo\init.lua'
 no file 'C:\Program Files (x86)\Lua\5.1\demo.lua'
 no file 'C:\Program Files (x86)\Lua\5.1\demo\init.lua'
 no file 'C:\Program Files (x86)\Lua\5.1\lua\demo.luac'
 no file '.\demo.lua'
 no file 'C:\Program Files (x86)\Lua\5.1\lua\demo.lua'
 no file 'C:\Program Files (x86)\Lua\5.1\lua\demo\init.lua'
 no file 'C:\Program Files (x86)\Lua\5.1\demo.lua'
 no file 'C:\Program Files (x86)\Lua\5.1\demo\init.lua'
 no file 'D:\Game\5.1\lua\demo.luac'
 no file '.\demo.dll'
 no file '.\demo51.dll'
 no file 'C:\Program Files (x86)\Lua\5.1\demo.dll'
 no file 'C:\Program Files (x86)\Lua\5.1\demo51.dll'
 no file 'C:\Program Files (x86)\Lua\5.1\clibs\demo.dll'
 no file 'C:\Program Files (x86)\Lua\5.1\clibs\demo51.dll'
 no file 'C:\Program Files (x86)\Lua\5.1\loadall.dll'
 no file 'C:\Program Files (x86)\Lua\5.1\clibs\loadall.dll'

找不到就会提示报错!

package.loaded是什么?

require会将返回值存储到table package.loaded中;若是加载器没有返回值,require就会返回table package.loaded中的值。能够看到,咱们上面的代码中,模块没有返回值,而是直接将模块名赋值给table package.loaded了。这说明什么,package.loaded这个table中保存了已经加载的全部模块。如今咱们就能够看看require究竟是如何加载的呢?

1.先判断package.loaded这个table中有没有对应模块的信息;
2.若是有,就直接返回对应的模块,再也不进行第二次加载;
3.若是没有,就加载,返回加载后的模块。

1.从require传入的参数中获取模块名;
2.创建一个空table;
3.在全局环境_G中添加模块名对应的字段,将空table赋值给这个字段;
4.在已经加载table中设置该模块;
5.设置环境变量。

就是这几步,在每个模块的定义以前都须要加上,是否是有点麻烦,在Lua5.1中提供了一个新函数module,它包括了以上这些步骤完成的功能。

相关文章
相关标签/搜索