Lua提供了一个名为require的高层函数来加载模块,但这个函数只假设了关于模块的基本概念。

对于require而言,一个模块就是一段定义了一些值(函数或者包含函数的table)的代码。

为了加载一个模块,只需要简单调用require "modname" 。这个函数首先会查找package.loaded表,检查modname是否加载过。

如果加载过,require返回package.loaded[modname]中的值。

否则,它试着为模块寻找“加载器”。

首先require会搜寻Lua file 。如果找到lua文件,就调用loadfile加载,它的返回值是函数 即"加载器"。

如果找不到Lua文件,会寻找C库,如果找到,就调用package.loadlib加载,去寻找luaopen_modname标志函数。

每次找到加载器,require就用两个参数调用加载器:modname和一个在获取加载器过程中得到的参数(如果通过查找文件得到的加载器,这个额外参数就是文件名)。

如果加载器返回非空值,require将这个值赋给package.loaded[modname].否则也会为其设置true值,无论什么情况,require都会返回package.loaded[modname]的最终值。如果在加载或运行时有错误,或是无法为模块找到加载器,require都会抛出错误。

如果要用require加载模块两次,我们可以把package.loaded[modname]给擦除掉。

packag.loaded.[modname] = nil

有时需要讲一个模块改名,以避免名字冲突。比如同一个模块有不同版本的情况。对于一个lua文件来说,改掉名字就可以了。

但是对于一个C程序库,我们就不能编辑其中的luaopen_*函数的名称了。为此,require用到了一个小技巧:

如果一个模块中包含了连字符 " - " ,require就会用连字符后的内容来创建luaopen_*函数名。

比如一个模块名为module-hello,require就会认为它的open函数是luaopen_hello,并不是luaopen_a-b。

因为在C语法中,连字符作为函数名是非法的。

因此,如果我们需要用两个同名的mod模块,可以把其中一个重新命名为mod-hello,一个命名为mod-world。

当调用

m1 = require "mod-hello"

require函数会找到这个mod-hello文件,并且在这个文件里,去找luaopen_mod函数。

注意:Lua5.2与Lua5.3这里是完全相反:5.2移除"-"之前的,5.3移除“-”之后的。

Lua5.3的版本,如果遇到a.b.c-v2.1的模块名,函数名就是luaopen_a_b_c。横线后的都忽略掉。

路径搜索

  当搜索一个Lua文件的时候,rquire用的的路径是一系列样板(templates),其中的每一个指定了模块的文件名。

在每个路径样板中都包含了一个可选的'?'符号,require会用模块名去替代这个问号(如果有的话),再去检查这个文件是否存在。

如果该样板没有,就从下一个样板继续寻找。这些路径样板被";"一个个隔开:

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

require "mod" 语句会寻找下面的文件:

mod
mod.lua
c:\Windows\mod
/usr/loacl/lua/mod/mod.lua

require只处理 ";" 和 "?" 符号,其他符合则是路径自己定义的。

require找lua文件时路径变量是package.path。Lua一开始会用LUA_PATH_5_3环境变量去初始化它。

如果没有定义这个环境变量,就会用LUA_PATH。如果两个都没有定义,Lua会用luaconf.h里的默认路径。

环境变量中出现的所有“;;”都会被替换成默认路径。

比如你把LUA_PATH_5_3设置为“mydir/?.lua;;”,最后的路径会是"mydir/?.lua"之后跟着的是默认路径。

require寻找C库的方法也是一样的,但是变量变成了package.cpath。初始化的时候使用的是LUA_CPATH_5_3和LUA_CPATH。

在UNIX中是这样的:

./?.so;/usr/local/lib/lua/5.3/?.so

package.searchpath函数包含了所有搜寻库的规则,它接收一个模块名和一个路径。

路径是一系列以分号分隔的模板构成的字符串,在其中搜索指定的name。

返回第一个可以用读模式打开(并马上关闭该文件)的文件的名字。如果不存在这样的文件,即返回nil加上错误消息。

该错误消息列出所有尝试打开的文件名。

搜寻器

  用于require控制如何加载模块的表--package.searchers

表内的每一项都是一个查找器函数,当查找一个模块时,require按照次序调用这些查找器,并传入唯一的模块名参数。

成功则返回另一个函数(模块的加载器)和一个加载器需要的参数。nil则表示错误。

Lua用四个查找器函数初始化该表:

1>  在package.preload表中查找加载器,没有返回值。

2>  查找Lua库的加载库,用存储在package.path中的路径来查找

3>  查找C库的加载库,使用存储在package.cpath中的路径。

4>  一体化加载器,从C路径中查找指定模块的根名字。例如“a.b.c”;它将查找a这个库。如果找到就会在里面找子模块的加载函数,就是找luaopen_a_b_c。

比如查找 “hello.core” 模块,就是寻找hello库的core子模块。对应的函数就是luaopen_hello_core。

这样可以把若干C子模块打包进单个库。每个子模块都可以有原本的加载函数名。

以上内容来自:《Lua程序设计第二版》和《Programming in Lua  third edition 》

Chapter 15_1 require函数的更多相关文章

  1. 【前端】require函数实现原理

    // require函数实现原理: function require(modulePath) { var regExp = /\w+$/g; var moduleName = regExp.exec( ...

  2. Lua Require函数

    转自:http://www.cppblog.com/cslover/archive/2013/12/21/204934.html Lua提供高级的require函数来加载运行库.粗略的说require ...

  3. WAP调用微信支付https://pay.weixin.qq.com/wiki/doc/api/wap.php?chapter=15_1

    公司做的一个购物网站 之前微信版的网站要搬在webView上   可是微信支付是个问题 , 在外部浏览器怎么都发不起微信请求 , 原因是因为页面调用的微信浏览器自带JSAPI 在外部浏览器无法调用,但 ...

  4. luci 中require函数包含的路径

    在 lua 脚本中常用的包含某个文件就是 require 函数. 例如: #!/usr/bin/lua                     // 表明使用的是lua脚本,像shell脚本一样 lo ...

  5. JS中require函数的警告提示

    在JS中常常使用require函数来引入文件或者路径,不过在使用时需要注意一点,它的参数必须是一串完整的字符串常量或者是由字符常量与变量拼接. (一)require函数的参数为一个变量,如下图所示: ...

  6. Chapter 21_2 模式匹配函数

    基础函数比较简单,就是几个普通的函数string.byte.string.char.string.rep.string.sub.string.format还有大小写转换函数upper和lower. 接 ...

  7. PHP的require()函数可以在一行代码中多次读取

    [root@NJ232:~]$[root@NJ232:~]$more tt.php m#!/opt/php/bin/php -q<?phpwhile(1){ sleep(2); $arr = r ...

  8. Chapter 21_1 字符串函数

    接下来开始接触Lua强大的字符串处理能功能——字符串库. 原始的Lua解释器操作字符串的能力很有限,真正强大的能力还是来自字符串库. 它所有的函数都在模块string中.它还为strings设置了一个 ...

  9. Chapter 17_2 备忘录函数

    一项通用的编程技术:用空间换时间. 例如有一种做法就可以提高一些函数的运行速度,记录下函数计算的结果,当再次调用该函数时,便可以复用之前的结果. 比如,一个普通服务器,在它收到请求中包含Lua代码,会 ...

随机推荐

  1. Win10下Mysql5.7.13,解压版安装流程

    一.环境变量配置 1.将下载好的压宿包解压到安装目录,我的安装目录就是:D:\DevelopmentTool\Mysql5.7.13\mysql-5.7.13-winx64 2.鼠标选择计算机右键,点 ...

  2. 引用AForge.video.ffmpeg,打开时会报错:找不到指定的模块,需要把发行包第三方文件externals\ffmpeg\bin里的dll文件拷到windows的system32文件夹下。

    引用AForge.video.ffmpeg,打开时会报错:找不到指定的模块,需要把发行包第三方文件externals\ffmpeg\bin里的dll文件拷到windows的system32文件夹下. ...

  3. Apache php无法开启php_curl

    解决办法: 将php安装目录下的libeay32.dll,libssh2.dll,php5ts.dll,php_curl.dll,ssleay32.dll 复制到system32目录下 在httpd. ...

  4. [SOJ] 导游

    Description Mr. G. 在孟加拉国的一家旅游公司工作.他当前的任务是带一些游客去一些遥远的城市.和所有国家一样,一些城市之间有双向道路.每对相邻城市之间都有一条公交路线,每条路线都规定了 ...

  5. 无法定位程序输入点__gxx_personality_v0的一个解决方法

    windows系统,使用mingw32-g++编译一个简单的工程,编译链接过程都没有错误提示,但是运行的时候会弹出提示框提示"无法定位程序输入点__gxx_personality_v0&qu ...

  6. 简单的jquery ajax文件上传功能

    /* * 图片上传 * 注意如果不加processData:false和contentType:false会报错 */ function uploadImage(image) { var imageF ...

  7. iPhone doesn’t support any of GongShangJ.app’s architectures. You can add iPhone’s armv7s architectu

    iPhone doesn't support any of GongShangJ.app's architectures. You can add iPhone's armv7s architectu

  8. TCP/IP 协议(摘抄)

    TCP/IP 协议 TCP/IP 是不同的通信协议的大集合. 协议族 TCP/IP 是基于 TCP 和 IP 这两个最初的协议之上的不同的通信协议的大集合. TCP - 传输控制协议 TCP 用于从应 ...

  9. Android Game Examples

    Game2 using UnityEngine; using System.Collections; public class Game2_Player : MonoBehaviour { publi ...

  10. proc中tran的一般处理

    存储过程事物的处理 一般情况在proc中判断的处理我们都采用 ) begin select '错误' return end 而在tran中我们最好用抛异常的方式 begin try begin SET ...