module require区别
【lua 5.1 的 module】
lua 从 5.1 开始终于官方提供统一的 module 实现标准了,这是个值得庆幸的事。今天读了下相关的源码和文档,把这套机制搞清楚了,还是很巧妙的。从简洁这个角度看,要比 python 强 :)
有一点容易被忽略掉(我的同事在用的时候就忽略掉了),module 指令运行完后,整个环境被压栈,所以前面全局的东西再看不见了。比如定义了一个 test 模块,使用
module("test")
后,下面不再看的见前面的全局环境。如果在这个模块里想调用 print 输出调试信息怎么办呢?一个简单的方法是
local print=print
module("test")
这样 print 是一个 local 变量,下面也是可见的。或者可以用
local _G=_G
module("test")
那么 _G.print 也是可以用的。
当然还有一种巧妙的方式,lua 5.1 提供了一个 package.seeall 可以作为 module 的option 传入
module("test",package.seeall)
这样就 OK 了。至于它们是如何工作的,还是自己读源码会理解的清楚一些。
在读源码时可以发现很多 lua 的技巧,还有一些 undocumented 的东西,比如 newproxy :) 它是一个 unsupported 且 undocumented 的东西,但是它希望实现的却是个巧妙的玩意。
功能:建立一个模块。
当package.loaded[name]中存在时,当中的表作为module;
当在全局表中存在name指定的表时,此表作为module;
当以前两种情况都不存表name时,将新建一个表,并使其作为全局名name的值,并package.loaded[name],而且设 t._NAME为name,t._M为module,t._PACKAGE为包的全名(模块名-组件a.b.c);最后把此module设t作为当前函数 的新环境表和package.loaded[name]的新值(也就是说,旧的环境表将不能访问,除了加上package.seeall参数外),以被 require使用
module(name)后的可选参数为接收module名的函数,如package.seeall
【lua 5.1 的 require】
require (modname)
功能:加载指定的模块。
此函数先检测package.loaded表中是否存在modname,存在则直接返回当中的值,没有则通过郰定义的加载器加载modname。
查找加载器顺序:
(1)检测package.preload表是否存在modname,有则加载
(2)通过Lua Loader加载,通过查找存放于package.path的路径加载,有则加载
(3)通过C Loader加载,通过查找存放于package.cpath的路径加载,有则加载
(4)通过all-in-one Loader加载:
通过查找modname.dll并查找当中的luaopen_
其中XXXX为载块名-后的字符用_替换.后的字符:如:a.v1-b.c 当函数名为luaopen_b_c
当require查找的不是一个Lua库或C库,它就会调用all-in-one loader,此加载器是用C路径作为载块的目录,
当查找到合适的加载器时,require就会加载其中的模块,当加载器有返回值,将会存放于package.loaded[modname]表。最后返回package.loaded[modname]表
当加载失败时,require将触发错误
3、package.cpath
功能:用于require C loader的搜索路径
可以通过修改LUA_CPATH变量(luaconf.h)修改此值
4、package.loaded
功能:一个用于让require知道哪些模块已加载的记录表,如果package.loaded已经有require要的值,则直接返回此值
5、package.loadlib (libname, funcname)
功能:通过动态连接C函数库方式加载Lua扩展库
libname为库文件名,funcname为入口函数(此函数必须为纯C接口函数 c++则需用 extern "C" {} 进行限制)
6、package.path
功能:用于require Lua loader的搜索路径
可以通过修改LUA_PATH变量(luaconf.h)修改此值
7、package.preload
功能:一个用于保存特殊模块加载器的表
8、package.seeall(module)
功能:为module设置一个元表,此元表的__index字段的值为全局环境_G。所以module可以访问全局环境
注:以此函数作为module()的一个选项(详细见module()
注意:require只认文件名,不认路径名。要加入路径名信息的话,就要写成父模块子模块的形式。
比如说,我有两个文件夹 testa, testb,在每个文件夹里面都有一个run.lua文件。我先在lua里面chdir进到testa里面去require了一下run.lua,然后再 chdir出来,再chdir进testb,然后,再执行require "run"。
这个时候,Lua是默认不会把第二个文件夹中的 run.lua给加载进来的,因为Lua会对加载进来的所有模块有一个按名字的管理系统,记录在 package.loaded 里面。如果要强制加载新的run.lua文件,就得把老的模块记录给清掉,即使用 package.loaded["run"] = nil,然后再加载。
实际上,Lua这样设计的目的是为了防止对模块的重复加载──这样可以解决开发过程中经常遇到的重复包含的问题,还可解决递归包含的问题。我们通常在C语言的头文件中写上#ifdef #define #endif之类的结构,也是为了实现这种效果。
任何设计都不是万能的,需要开发者根据实际情况灵活变通。
module require区别的更多相关文章
- module.exports,exports,export和export default,import与require区别与联系【原创】
还在为module.exports.exports.export和export default,import和require区别与联系发愁吗,这一篇基本就够了! 一.首先搞清楚一个基本问题: modu ...
- module.exports,exports,export和export default,import与require区别与联系
还在为module.exports.exports.export和export default,import和require区别与联系发愁吗,这一篇基本就够了! 一.首先搞清楚一个基本问题: modu ...
- 通过ES6 Module看import和require区别
前言 说到import和require,大家平时开发中一定不少见,尤其是需要前端工程化的项目现在都已经离不开node了,在node环境下这两者都是大量存在的,大体上来说他们都是为了实现JS代码的模块化 ...
- CommonJS 规范中的 module、module.exports 区别
CommonJS 规范中的 module.module.exports 区别 CommonJS规范规定,每个模块内部,module变量代表当前模块.这个变量是一个对象,它的exports属性(即mod ...
- import()、import语句、require() 区别
import命令能够接受什么参数,import()函数就能接受什么参数,两者区别主要是后者为动态加载. import() 与 import语句 区别 区别项 import() import语句 参数都 ...
- Android 培训准备资料之project与module的区别(1)
project和module的区别? 现在我们来看看在Android studio中怎样新建一个project (1)file->new->new project. Application ...
- ES6学习笔记(二)—— 通过ES6 Module看import和require区别
前言 说到import和require,大家平时开发中一定不少见,尤其是需要前端工程化的项目现在都已经离不开node了,在node环境下这两者都是大量存在的,大体上来说他们都是为了实现JS代码的模块化 ...
- node exports和module.exports区别
我们只需知道三点即可知道 exports 和 module.exports 的区别了: exports 是指向的 module.exports 的引用 module.exports 初始值为一个空对象 ...
- exports和module.exports区别
参考:module.exports与exports的区别.关于exports的总结 exports 和 module.exports 的区别 module.exports是真正的模块接口,而expor ...
随机推荐
- Scala-Partial Functions(偏函数)
如果你想定义一个函数,而让它只接受和处理其参数定义域范围内的子集,对于这个参数范围外的参数则抛出异常,这样的函数就是偏函数(顾名思异就是这个函数只处理传入来的部分参数). 偏函数是个特质其的类型为Pa ...
- [Ionic] Build and Run an Ionic App from Scratch
Install: npm install ionic cordova -g Create a project with blank template: ionic start <project_ ...
- ThinkPHP实现跨模块调用操作方法概述
ThinkPHP实现跨模块调用操作方法概述 投稿:shichen2014 字体:[增加 减小] 类型:转载 使用 $this 可以调用当前模块内的方法,但是很多情况下经常会在当前模块中调用其他模块 ...
- WEB服务器3--IIS7.0安装和配置
安装Web服务器(IIS) 点击开始菜单->所有程序->管理工具->服务器管理器,启动服务器管理器,界面如下: 在服务器管理器中,选择角色,你将可以看到角色总视图. 点击添加角色,会 ...
- js实现的对象数组根据对象的键值进行排序代码
有时候会遇到做展示数组的排序,由大到小和由小到大的切换: var arr=[{id:1,webName:"蚂蚁部落"},{id:2,webName:"网易"}] ...
- 一个很经典的this面试题
!function(){ this.length = 10; var fn = function(){ console.log(this.length); //输出多少? }, arr = [fn, ...
- 最强烈推荐-我的java收藏夹(内有国内最好的java论坛)
原地址: http://bbs.chinaitlab.com/dispbbs.asp?boardid=148&id=34276 国内: www.chinajavaworld.com-论坛人很多 ...
- hdu 1042 N!(高精度乘法)
Problem Description Given an integer N(0 ≤ N ≤ 10000), your task is to calculate N! Input One N in ...
- tomact虚拟目录,虚拟主机,http请求头,相应头
tomact虚拟目录,虚拟主机,http请求头,相应头 07. 五 / J2EE / 没有评论 一.服务器,容器(软件)1.服务器:提供网络访问的程序2.容器:支持什么技术的服务器就叫做什么容器. ...
- easyui的combobox将得到的数据设定为下拉框默认值和复选框设定默认值
通过easyui做了一个表,表里是从数据库拿到的数据. 现在双击某一行,通过点击行的id取到这一行的所有数据,现在需要修改这些得到的数据, 其中部分数据是<select>这个选择的, 问题 ...