Lua的模块与包机制
2015-03-22 14:31
148 查看
从用户的观点来看,一个模块就是一个程序库,可以通过require来加载。然后得到了一个全局变量,表示一个table。
这个table就像一个名称空间,其内容就是模块中导出的所有东西,比如函数和变量。一个规范的模块还应该使得require返回这个table。
显然,在Lua中,模块也是"第一类值"。
比如,用户需要调用一个模块中的函数,最简单的方法:
require "mod"
mod.foo
如果希望能使用较短的模块名称,则可以为模块设置一个全局名称:
local m = require "mod"
m.foo()
还可以为个别函数设置不同的名称:
require "mod"
local f = mod.foo
f()
require 函数细节
require函数加载模块时,会检查package.loaded是否已经加载。所以一个模块只会加载一次。
如果require为指定模块找到了一个Lua文件,它就会通过loadfile来加载该文件。如果找到的是一个C程序库,就通过loadlib来加载。请注意loadfile和loadlib都只是加载了代码,并没有运行它们。为了运行代码,require会以模块名作为参数来调用这些代码。
require用于搜索Lua文件的路径放在常量package.path中。当Lua启动后,便以环境变量LUA_PATH的值来初始化这个变量。如果没有找到这个环境变量,则使用一个编译时定义的默认路径来初始化。
如果require无法找到和模块相符的Lua文件,就会寻找C程序库。这类搜索是从变量package.cpath来获取路径。
模块的创建方法
在Lua中创建一个模块的最简单方法是:创建一个table,并将所有需要导出的函数放入其中,最后返回这个table。
比如:
在这里,必须显示地将模块名放到每个函数的定义中。而且在函数定义中,一个函数调用另外一个函数,必须限定使用被调用函数的名称。
但是,我们是没有必要写模块名字的,因为require会将模块名字作为参数传递给模块。
另外一个改进是不需要return 模块名字了。因为,如果一个模块没有返回值的话,require就会返回package.loaded[modname]的当前值。
现在的创建模块的基本方法缺点在于:在访问同一模块的其他方法时候,必须限定名称。通过使用"函数环境"这种技术,可以解决这个问题。
这里add函数就从环境中得到new也就是complex.new。但是由于使用了环境,会导致访问其他模块出现问题。比如访问全局模块_G。
一般较好的解决办法是将需要用到的模块声明为局部变量:
在Lua5.1后,Lua提供了一个新函数modle,包括了:
这些功能。默认情况下,module不提供对外访问。必须在调用它之前,为所需要访问的外部函数或者模块声明恰当的局部变量。也可以通过继承来实现外部访问。只需要在module时候加一个选项package.seeall。这个选项等价于以下代码:
setmetatable(M, {__index = _G}),只需要这么做:module(..., package.seeall)
这个table就像一个名称空间,其内容就是模块中导出的所有东西,比如函数和变量。一个规范的模块还应该使得require返回这个table。
显然,在Lua中,模块也是"第一类值"。
比如,用户需要调用一个模块中的函数,最简单的方法:
require "mod"
mod.foo
如果希望能使用较短的模块名称,则可以为模块设置一个全局名称:
local m = require "mod"
m.foo()
还可以为个别函数设置不同的名称:
require "mod"
local f = mod.foo
f()
require 函数细节
require函数加载模块时,会检查package.loaded是否已经加载。所以一个模块只会加载一次。
如果require为指定模块找到了一个Lua文件,它就会通过loadfile来加载该文件。如果找到的是一个C程序库,就通过loadlib来加载。请注意loadfile和loadlib都只是加载了代码,并没有运行它们。为了运行代码,require会以模块名作为参数来调用这些代码。
require用于搜索Lua文件的路径放在常量package.path中。当Lua启动后,便以环境变量LUA_PATH的值来初始化这个变量。如果没有找到这个环境变量,则使用一个编译时定义的默认路径来初始化。
如果require无法找到和模块相符的Lua文件,就会寻找C程序库。这类搜索是从变量package.cpath来获取路径。
模块的创建方法
在Lua中创建一个模块的最简单方法是:创建一个table,并将所有需要导出的函数放入其中,最后返回这个table。
比如:
complex = {} function complex.new(r, i) return {r=r, i=i} end -- 定义一常量 complex.i = complex.new(0,1) function complex.add(c1,c2) return complex.new(c1.r + c2.r, c1.i + c2.i) end function complex.sub(c1, c2) return complex.new(c1.r - c2.r, c1.i - c2.i) end .... return complex
在这里,必须显示地将模块名放到每个函数的定义中。而且在函数定义中,一个函数调用另外一个函数,必须限定使用被调用函数的名称。
但是,我们是没有必要写模块名字的,因为require会将模块名字作为参数传递给模块。
local modname = ... local M = {} _G[modname] = M package.loaded[modname] = M M.i = {r = 0, i = 1} function M.new(r, i) return {r=r, i=i} end function M.add(c1, c2) return M.new(c1.r + c2.r, c1.i + c2.i) end ...
另外一个改进是不需要return 模块名字了。因为,如果一个模块没有返回值的话,require就会返回package.loaded[modname]的当前值。
现在的创建模块的基本方法缺点在于:在访问同一模块的其他方法时候,必须限定名称。通过使用"函数环境"这种技术,可以解决这个问题。
local modname = ... local M = {} _G[modname] = M package.loaded[modname] = M setfenv(1, M) function M.new(r, i) return {r=r, i=i} end function add(c1, c2) return new(c1.r + c2.r, c1.i + c2.i) end ...
这里add函数就从环境中得到new也就是complex.new。但是由于使用了环境,会导致访问其他模块出现问题。比如访问全局模块_G。
一般较好的解决办法是将需要用到的模块声明为局部变量:
local modname = ... local M = {} _G[modname] = M package.loaded[modname] = M -- 导入 local sqrt = math.sqrt local io = io setfenv(1, M)
在Lua5.1后,Lua提供了一个新函数modle,包括了:
local modname = ... local M = {} _G[modname] = M package.loaded[modname] = M setfenv(1, M)
这些功能。默认情况下,module不提供对外访问。必须在调用它之前,为所需要访问的外部函数或者模块声明恰当的局部变量。也可以通过继承来实现外部访问。只需要在module时候加一个选项package.seeall。这个选项等价于以下代码:
setmetatable(M, {__index = _G}),只需要这么做:module(..., package.seeall)
相关文章推荐
- Lua内置库的实现(一)_math模块(一)_从math模块看Lua的模块注册机制
- 第四章 Lua模块开发
- Python Import机制备忘-模块搜索路径(sys.path)、嵌套Import、package Import
- lua开发之--mysql和http模块
- Lua使用动态链接库调用C模块(VS2015)
- ngx_lua模块学习示例之waf
- 闭包的总结(干货2)--模块机制
- mac下Nginx+lua模块编译安装
- Lua中的模块(module)和包(package)详解
- WebRTC的模块处理机制
- QT 下调用lua自定义模块
- ulua 路径小记 以及 lua require 机制整理
- nodejs快速入门(三)-模块引入与加载机制
- 突破SafeSEH机制之三——利用加载模块之外的地址绕过SafeSEH
- Lua cjson模块编译笔记及错误解决方法
- 高可用集群heartbeat模块可靠消息通信机制过程原理
- 探索 OpenStack 之(17):计量模块 Ceilometer 中的数据收集机制
- gx_Lua模块中的重定向
- 利用bigpipe机制实现页面模块的异步渲染 chunked技术
- 【深入浅出node.js】读书摘录2 - node.js模块机制