lua中module和require解析

前言

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

require函数

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

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

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

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

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

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

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

 ;.\?.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会以模块名作为参数来调用这些代码。

如果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,它包括了以上这些步骤完成的功能。

转载于:https://my.oschina.net/u/223340/blog/634162

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值