爱开发联盟是国内专业的网站建设资源、脚本编程学习类网站,提供asp、php、asp.net、javascript、jquery、vbscript、dos批处理、网页制作、网络编程、网站建设等编程资料。让开发变得简单起来!
爱开发联盟是国内专业的网站建设资源、脚本编程学习类网站,提供asp、php、asp.net、javascript、jquery、vbscript、dos批处理、网页制作、网络编程、网站建设等编程资料。让开发变得简单起来!
当前所在位置:主页 > 脚本 > Lua >
  • 魔艺客提供SEO\SEM推广整合营销服务
  • 提供整套互联网营销整合方案-魔艺客
  • 魔艺客高端网站建设开发服务十一大优惠服务
  • 资深的网站建设开发经验,一对一服务-魔艺客高
  • 一站式服务,从服务器到网站,三站何以尽在魔
爱开发联盟是国内专业的网站建设资源、脚本编程学习类网站,提供asp、php、asp.net、javascript、jquery、vbscript、dos批处理、网页制作、网络编程、网站建设等编程资料。让开发变得简单起来!

Lua中模块以及实现方法指南

发布时间:2017-09-08 19:42    作者:爱开发联盟    浏览:次    来源:aikaifa.com.cn 分享:

从使用的角度来看,一个模块就是一个程序库,可以通过Lua自身提供的require来加载。然后便得到一个全局变量,表示一个table。这个table就是像一个名字空间,其内容就是模块导出的所有东西,例如函数和常量。简单的说,Lua中的模块就是一个table,table中可以包括任何东西。本文首先详细介绍模块相关的require函数,包括该函数的执行流程以及查找模块的路径,然后介绍了实现模块的三种方法,并给出相应的优缺点。

 require函数

     该函数用来加载一个模块,即按指定的路径和传入的参数,查找要加载的模块。函数原型如下:

      require (modname)

      该函数的执行流程如下:

      I、查找表package.loaded,看modname是否已经加载过了。若是,则require函数直接返回package.loaded[modname],否则继续执行,寻找模块的加载器(loader)。

      II、为了寻找加载器,require使用了数组package.searchers(Lua 5.2引入的,在之前的版本叫做package.loaders,实质两者只是名字不同而已),数组中每个元素是一个函数。

     第一个函数用来是搜索表package.preload,若存在,则返回相应的加载器。

     第二个函数是用来获取Lua模块的加载器,其搜索路径存储在package.path中,它是一个字符串,比如:

代码如下:

/usr/local/share/lua/5.2/?.lua;/usr/local/share/lua/5.2/?/init.lua;/usr/local/lib/lua/5.2/?.lua;/usr/local/lib/lua/5.2/?/init.lua;./?.lua 

会用模块名来替换每个”?”,然后根据替换的结果来检测是否存在这样的一个文件。这个工作是通过函数package.searchpath来做的。package.searchpath函数原型如下:
      package.searchpath (name, path [, sep [, rep]])

参数path是要查找的字符串,用分号隔开;name是要查找的文件;参数sep(默认值是”.”)可用于name中,在查找过程中用rep(默认值是系统目录的分隔符)替换。比如path是

代码如下:

"./?.lua;./?.lc;/usr/local/?/init.lua"

要查找foo.a,则会尝试查找文件

代码如下:

./foo/a.lua, ./foo/a.lc, 和/usr/local/foo/a/init.lua 

也就是说Lua支持具有层级性的模块名。
      第三个函数是用来获取C模块的加载器,其搜索路径存储在package.cpath中,它也是一个字符串,比如:

代码如下:

/usr/local/lib/lua/5.2/?.so;/usr/local/lib/lua/5.2/loadall.so;./?.so 

同样会用模块名来替换每个”?”,然后根据替换的结果来检测是否存在这样的一个文件。这个工作也是通过函数package.searchpath来做的。
     第四个函数是用all-in-one 加载器,使用这个功能,可以使得一个包里面包含多个C子模块。除了第一个外,其他三个除了返回加载器外,还会返回找到的文件名作为额外的值。

      III、找到加载器后,require将用两个参数调用这个加载器,一个是传入的参数modname,另外一个是返回的额外值。如加载器返回一个不是nil的值,则把这个值赋值给package.loaded[modname]。如果加载返回返回一个nil并且加载器执行完后package.loaded[modname]还为空,则把package.loaded[modname]赋值为true。不管那种情况,require都会返回package.loaded[modname]。如果在这个过程有任务错误,require函数就产生一个错误给调用者。

     最后关于require函数,值得注意的几点是:

     I、如果require找到的是一个lua文件,则通过loadfile来加载代码,如果找到的是一个C程序库,就通过loadlib来加载。注意,loadfile和loadlib都实质上加载代码,并没有运行他们。为了运行他们,require会用模块名作为参数来调用这些代码。

     II、若要强制使require对同一库加载两次,可以简单删除package.loaded中的模块条目,即赋值相应的条目为nil。

     III、通过上面的加载过程分析知道,要加载自己的lua文件或C库,可以通过修改package.path或package.cpath的值,把要搜索的路径加载进去。

      IV、也可以定义自己的加载函数(除了已有的loadlib和loadfile等),比如加载ZIP文件,甚至从web上下载一个文件。

编写模块的方法

     方法一:对于Lua5.0和5.1来说,编写模块最简单的方法是使用Lua自身提供的module函数(注意在Lua 5.2中被删除了),比如要编写一个模块foo,模块文件foo_file.lua如下:

代码如下:

module("foo", package.seeall) 
function test() 
end 

则在其他文件要使用这个模块,方式如下:

代码如下:

require(“foo_file.lua”) 
foo.test() 

并且执行require后,则会把模块foo就是全局环境的一个变量了,在其他地方也可以使用。module函数原型如下:

代码如下:

module (name [, ···]) 

module在创建模块table之前,会先检查package.loaded是否已包括了这个模块,或者是否已存在与模块同名的变量。如果由此找到了这个table,它就会复用这个table做为模块。也就是说,可以用module来打开一个已创建的模块。

对于module函数来说,有以下问题,比如在模块文件module0_test中有:

代码如下:

module("mymodule", package.seeall)                                                                      
function foo() 
    print("Hello World!") 
end 

在另外一个文件可以这样使用这个模块:

代码如下:

require "module0_test" 
mymodule.foo()             --Hello World! 
mymodule.print("example")  --example 

对于第二个调用不是报错的,并且是非常奇怪的,这时因为module机制是在模块中找不的成员,则去_G全局变量找,实现方式类似如下:

do 
  local globaltbl = _G 
  local newenv = setmetatable({}, { 
    __index = function (t, k) 
      local v = t[k] 
      if v == nil then return globaltbl[k] end 
      return v 
    end, 
    __newindex = M, 
  }) 
  if setfenv then 
    setfenv(1, newenv) -- for 5.1 
  else 
    _ENV = newenv -- for 5.2 
  end 
end 

在模块找不到的成员,则到_G中去查找,并且这样访问也是非常低效的,因为要通过元表来访问成员。

 方法二:该方法的基本思想是让模块的主程序有一个独占的环境,这样所有函数或变量都共享这个table,并且所有的全局变量都记录在这个table中,当然局部变量是不会的。代码片段如下:

local modename = ... 
local M = {} 
_G[modename] = M 
package.loaded[modname] = M 
if setfenv then 
  setfenv(1, newenv) -- for 5.1 
else 
  _ENV = newenv -- for 5.2 
end 

如果这样实现,在模块访问_G中的变量时,需要加上前缀,比如_G.print。为了解决这个问题,有几种方法,各有优缺点:

 I、设置M的元表,即setmetable(M, {__index = _G})这样做后,访问全局变量,都要通过元表,开销比较大。

 II、设置local _G = _G,这样做后,访问全局变量仍然要加上前缀,但速度更快。

 III、把模块需要的全局变量都设置为局部变量,比如local io = io。这样做会比较繁琐,但是速度最快。

方法三:同样是使用环境的概念。比如模块文件如下:

代码如下:

function foo()                                                                                          
    print("Hello World!")                                                                               
end 

为了使用它,方法如下:

local function Import(filename)                                     
  f = loadfile(filename)                                        
  local M = {}                                             
  setmetatable(M, {__index = _G})                                   
  setfenv(f,M)() 
  return M 
end 
 
local FOO = Import("module2_test.lua") 
 
FOO.foo() --output “Hello World!” 

用这种方法,只需调用Import方法,其返回值就是模块,该方法把模块相关访问工作,放在使用的模块的地方了。

以上所述就是本文的全部内容了,希望能够对大家学习lua有所帮助。

网友评论

分类排行榜联系我们

好文推荐联系我们

爱开发联盟是国内专业的网站建设资源、脚本编程学习类网站,提供asp、php、asp.net、javascript、jquery、vbscript、dos批处理、网页制作、网络编程、网站建设等编程资料。让开发变得简单起来!
爱开发联盟是国内专业的网站建设资源、脚本编程学习类网站,提供asp、php、asp.net、javascript、jquery、vbscript、dos批处理、网页制作、网络编程、网站建设等编程资料。让开发变得简单起来!

当前最新内容联系我们

爱开发联盟是国内专业的网站建设资源、脚本编程学习类网站,提供asp、php、asp.net、javascript、jquery、vbscript、dos批处理、网页制作、网络编程、网站建设等编程资料。让开发变得简单起来!

在线手册

网站地图导航

前端 HTML/Xhtml HTML5 CSS XML/XSLT Dreamweaver教程 Frontpage教程 心得技巧 编程 JavaScript ASP.NET PHP编程 正则表达式 AJAX相关 ASP编程 JSP编程 Flex 脚本加解密 web2.0 XML/RSS 网页编辑器 相关技巧 安全相关 网页播放器 Dart 其它综合 脚本 VBS DOS/BAT HTA HTC Python perl 游戏相关 vba 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 脚本下载 广告代码 js框架 批处理 网页相关 源码下载 数据库 MsSql Mysql mariadb oracle DB2 mssql2008 mssql2005 SQLite PostgreSQL MongoDB Redis Access 数据库文摘 数据库其它 CMS dedecms ecshop z-blog UcHome UCenter 风讯CMS 科汛cms discuz 新云cms phpwind 动易cms phpcms 帝国cms WordPress drupal 其它cms 设计 photoshop教程 摄影教程 Fireworks教程 CorelDraw教程 Illustrator教程 Painter教程 Freehand教程 Indesign 设计素材 平面其它 微信相关 微信公众号 小程序 操作系统 bios 系统安装 系统进程 Windows系列 LINUX RedHat/Centos Ubuntu/Debian Fedora Solaris 麒麟系统 红旗Linux Unix/BSD 苹果MAC 注册表 其它系统 网站运营 建站经验 微信营销 网站优化 网站策划 网络赚钱 网络创业 站长故事 alexa域名 其它相关 网络安全 黑客教程 安全设置 杀毒防毒 病毒查杀 脚本攻防 黑客入侵 工具使用 业界动态 Exploit 漏洞分析 加密解密 手机黑客 安全其它 在线手册 网页制作 脚本编程 数据库相关 软件编程 系统相关 其它相关 源码下载

友情链接申请加入

51CTO 上海魔艺客 猫鼬设计开发 Erlo网站开发 猫鼬设计工作室 新发现全球资讯 信息安全与IT资讯
爱开发联盟是国内专业的网站建设资源、脚本编程学习类网站,提供asp、php、asp.net、javascript、jquery、vbscript、dos批处理、网页制作、网络编程、网站建设等编程资料。让开发变得简单起来!

283882409