Lua 基础之模块
来源:互联网 发布:oracle查看数据库名称 编辑:程序博客网 时间:2024/06/04 20:03
模块
模块系统的设计目标是可以使用不同的方式来共享代码,一个模块就是一个代码库,其它模块 可以使用 require 函数来加载,加载后得到模块导出的所有东西,如函数、常量、全局变量等。一个比较好的方式是让模块返回一个 table 并保存在一个全局变量中,然后外部模块直接使用这个全局变量来操作 table
模块定义–mod.lua
demo = {}demo.var = 100demo.foo = function() print("hello lua")endreturn demo
使用模块–main.lua
local m = require("mod")m.foo()demo.foo()print(m.var, demo.var)
require 函数
require 函数用于加载一个模块,其实现细节如下
function require(name) if not package.loaded[name] then local loader = findloader(name) if loader == nil then error("unable load module") end package.loaded[name] = true local res = loader(name) if res ~= nil then package.loader[name] = res end end return package.loaded[name]end
- 当加载一个模块时,会先在表 package.loaded 中查找该模块是否已经加载,如果已经加载了直接返回上次加载后的结果,因此重复调用 require 来加载同一个模块是不会出问题的
- 如果模块未加载,则试着为模块查找一个加载器,这个过程是在表 package.preload 中查询模块名,如果在其中找到一个函数则把该函数作为模块的加载器,上面代码使用 findloader 来抽象这个过程
- 接下来就是使用加载器来加载模块了,加载之前先把 package.loaded[name] 的值设为 true 这样可以避免两个模块交叉引用时陷入死循环;加载完成后把模块返回的值保存下来,如果模块没有显式地返回某个值,则返回的结果为 true
- 最后返回 package.laoder[name] 的值
编写模块的方法
返回一个 table
complex = {}complex.__index = complexcomplex.new = function(self, r, i) local o = {} setmetatable(o, self) o._r = r or 0 o._i = i or 1 return oendcomplex.add = function(self, c1, c2) return complex:new(c1._r + c2._r, c1._i + c2._i)endcomplex.get_r = function(self) return self._rendcomplex.get_i = function(self) return self._iendcomplex.set_r = function(self, v) self._r = vendcomplex.set_i = function(self, v) self._i = vendcomplex.i = complex:new(0, 1)return complex
使用 require 函数加载模块后会得到一个全局变量 complex,它的值就是模块定义的 table,通过 complex 变量就能访问和操作整个模块,这是模块最基本的写法
模块定义与使用分离
上面的例子中模块定义直接使用导出的模块名,这种方式看起来不是很规范,一种改进方法是将模块定义与导出的模块名分离,可以在模块内使用局部来定义 table,再将局部变量的值赋给导出变量
local M = {}M.__index = Mfunction M:new(r, i) local ins = {} setmetatable(ins, self) ins._r = r or 0 ins._i = i or 1 return insendfunction M:add(other) return M:new(self._r + other:get_r(), self._i + other:get_i())endfunction M:get_i() return self._iendfunction M:get_r() return self._rendfunction M:set_i(v) self._i = vendfunction M:set_r(v) self._v = vendM.i = M:new(0, 1)complex = Mreturn complex
自动模块名 & 隐藏返回值
local M = {}local mod_name = ..._G[mod_name] = Mpackage.loaded[mod_name] = MM.__index = Mfunction M:new(r, i) local ins = {} setmetatable(ins, self) ins._r = r or 0 ins._i = i or 1 return insendfunction M:add(other) return M:new(self._r + other:get_r(), self._i + other:get_i())endfunction M:get_i() return self._iendfunction M:get_r() return self._rendfunction M:set_i(v) self._i = vendfunction M:set_r(v) self._v = vendM.i = M:new(0, 1)
_G[mod_name] = M
创建了一个全局变量 mod_name = M
模块没显式写返回值,默认会返回 package.loaded[mod_name]
使用环境
现在定义模块都是在全局环境中完成时,这时不管数据的定义还是使用都得加上对应的前缀,而且如果定义私有变量时忘记加上 local 就会污染到全局环境。函数环境 让模块独占一个环境,这个环境与全局环境完全隔离,此时对模块而言,全局环境就是它自己的环境,因此它不能访问到真正的全局环境,也就是说不能访问其它基本模块,如果要使用全局环境中的模块,可以在使用 函数环境 前把这些模块保存到局部变量
使用 函数环境 后函数和变量的定义和使用都不需要加上模块前缀了
lua5.1 之前使用 函数环境 的方式是 setfenv(1,mod)
,5.3 的方式是 ENV = mod
local M = {}-- 模块名local mod_name = ...-- 保存到全局变量_G[mod_name] = M-- 保存到已加载模块package.loaded[mod_name] = Mlocal setmetatable = setmetatable-- 使用“函数环境”-- setfenv(1, M) -- 5.1local _ENV = M -- 5.3__index = Mnew = function(self, r, i) local o = {} setmetatable(o, self) o._r = r or 0 o._i = i or 1 return oendadd = function(self, other) return new(M, self._r + other._r, self._i + other._i)endget_i = function(self) return self._iendget_r = function(self) return self._rendset_i = function(self, v) self._i = vendset_r = function(self, v) self._v = vend
module 函数
使用 module 函数可以简化上面的模块定义
module(...)
等价于
local mod_name = ..._G[mod_name] = Mpackage.loaded[mod_name] = Msetfenv(1, M)
如果想访问原来的全局环境,则使用 module(... , package.seeall)
注意: 这是 lua5.1 之前定义模块的方法,5.3 并不建议使用 函数环境,这种方式会定义一个该模块的 table,然后注入到全局环境,这样虽然模块内的东西不会污染到全局环境,但整个模块会污染到全局环境,因为没有引用该模块的文件也能访问该模块内的函数或变量
- Lua 基础之模块
- Lua 基础之 Lua 程序
- Lua学习笔记之模块
- Lua之coroutine基础
- Lua基础之语法
- Lua基础之Function
- cocos2dx之lua基础
- Lua之coroutine基础
- Lua之coroutine基础
- Lua 基础之数据类型
- Lua 基础之语句
- Lua 基础之函数
- Lua 基础之迭代器
- Lua基础之函数
- Lua基础之字符串
- lua基础之数组
- lua基础之迭代器
- lua模块之cjson模块-json解析
- 编程实现字符串的替换
- StringBuilder 详解 (String系列之2)
- MFC:从“const CString”转换为“LPCSTR”
- mybatis 中使用if else 进行判断
- Ubuntu14.04下ruby的安装
- Lua 基础之模块
- 欢迎使用CSDN-markdown编辑器
- Activity界面启动和结束动画(仿微信界面切换效果)
- Hadoop之HBase框架学习(笔记15)
- python新手必碰到的问题---encode与decode,中文乱码
- mac 配置java home
- domain specific language
- POJ2031 Building a Space Station
- 百练_2700:字符替换