在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
转自:https://www.cnblogs.com/yyxt/p/3870236.html Lua提供高级的require函数来加载运行库。粗略的说require和dofile完成同样的功能但有两点不同: 1. require会搜索目录加载文件; 2. require会判断是否文件已经加载避免重复加载同一文件。 由于上述特征,require在Lua中是加载库的更好的函数。 (一) require require使用的路径和普通我们看到的路径还有些区别,我们一般见到的路径都是一个目录列表。require的路径是一个模式列表,每一个模式指明一种由虚文件名(require的参数)转成实文件名的方法。更明确地说,每一个模式是一个包含可选的问号的文件名。匹配的时候Lua会首先将问号用虚文件名替换,然后看是否有这样的文件存在。如果不存在继续用同样的方法用第二个模式匹配。例如,路径如下: ?;?.lua;c:\windows\?;/usr/local/lua/?/?.lua 调用require "test"时会试着打开这些文件: test test.lua c:\windows\test /usr/local/lua/test/test.lua require关注的问题只有分号(模式之间的分隔符)和问号,其他的信息(目录分隔符,文件扩展名)在路径中定义。 为了确定路径,Lua首先检查全局变量LUA_PATH是否为一个字符串,如果是则认为这个串就是路径;否则require检查环境变量LUA_PATH的值,如果两个都失败;require使用固定的路径(典型的"?;?.lua") require的另一个功能是避免重复加载同一个文件两次。Lua保留一张所有已经加载的文件的列表(使用table保存)。如果一个加载的文件在表中存在, 则require简单的返回;表中保留加载的文件的虚名,而不是实文件名。所以如果你使用不同的虚文件名require同一个文件两次,将会加载两次该文件。比如require "foo"和require "foo.lua",路径为"?;?.lua"将会加载foo.lua两次。我们也可以通过全局变量_LOADED访问文件名列表,这样我们就可以判断文件是否被加载过;同样我们也可以使用一点小技巧让require加载一个文件两次。比如,require "foo"之后_LOADED["foo"]将不为nil,我们可以将其赋值为nil,require "foo.lua"将会再次加载该文件。 一个路径中的模式也可以不包含问号而只是一个固定的路径,比如: ?;?.lua;/usr/local/default.lua 这种情况下,require没有匹配的时候就会使用这个固定的文件(当然这个固定的路径必须放在模式列表的最后才有意义)。在require运行一个chunk以前,它定义了一个全局变量_REQUIREDNAME用来保存被required的虚文件的文件名。我们可以通过使用这个技巧扩展require的功能。举个极端的例子,我们可以把路径设为"/usr/local/lua/newrequire.lua",这样以后每次调用require都会运行newrequire.lua,这种情况下可以通过使用_REQUIREDNAME的值去实际加载required的文件。 (二) dofile 我们知道一个lua文件是作为一个代码块(chunk)存在的,其实质就是一个函数,那么最简单的,我在一个外部lua文件中写一段代码,然后在主lua文件中用dofile调用,外部文件的代码块就会执行了。 外部lua文件在编译时并没有涉及词法域: 形式上很类似C语言的#include<...>,在其他地方定义的函数,经这么引入文件之后就可以调用了。不过lua并不是定义和实现分离的语言,这样是把整个定义部分都加载进来了。加载过程大致上是: lua先加载这个外部文件,然后运行它。实际上这段外部代码是可以有返回值的,它的返回值就是require的返回值。这里我们什么返回值都没有,执行这个外部代码的结果就是定义了这么个全局函数。注意是全局函数,虽然通常我们直接定义的函数 都是全局函数所以都没怎么注意过,要是非要定义个局部函数在主程序块里可就看不到了。另外和前面的情形一样,外部代码块只认识“雷叔”,“牛叔”是谁它根本不知道。 (三) lua中的require机制
"./?.lua;./?.lc;/usr/local/?/init.lua" 如果lua代码中调用:require("hello.world"), 那么lua会依次查找: ./hello/world.lua -- 这里"hello.world"变成了"hello/world",并替换了模型"./?.lua" ./hello/world.lc ..... (这种处理方式和python类似,只不过不需要__init__.py,也有调用python中的__init__.py) package.path在虚拟机启动的时候设置,如果存在环境变量LUA_PATH,那么就用该环境变量作为它的值,并把这个环境变量中的";;"替换为luaconf.h中定义的默认值,如果不存在该变量就直接使用luaconf.h定义的默认值. require(modelname) require(在lua中它是ll_require函数)的查找顺序如下: module(name, cb1, cb2, ...) a. 如果package.loaded[name]是一个table,那么就把这个table作为一个mod hello.world -- {["hello"]={["world"]={XXXXXXX}}} d. 依次调用cbs: cb1(mod), cb2(mod),... e. 将当前模块的环境设置为mod,同时把package.loaded[name] = mod |
请发表评论