当前位置: 首页 > news >正文

Lua的模块与包机制

从用户的观点来看,一个模块就是一个程序库,可以通过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。

比如:

 1 complex = {}
 2 
 3 function complex.new(r, i) return {r=r, i=i} end
 4 
 5 -- 定义一常量
 6 complex.i = complex.new(0,1)
 7 
 8 function complex.add(c1,c2)
 9     return complex.new(c1.r + c2.r, c1.i + c2.i)
10 end
11 
12 function complex.sub(c1, c2)
13     return complex.new(c1.r - c2.r, c1.i - c2.i)
14 end
15 
16 ....
17 
18 return complex

在这里,必须显示地将模块名放到每个函数的定义中。而且在函数定义中,一个函数调用另外一个函数,必须限定使用被调用函数的名称。

  但是,我们是没有必要写模块名字的,因为require会将模块名字作为参数传递给模块。

 1 local modname = ...
 2 local M = {}
 3 _G[modname] = M
 4 package.loaded[modname] = M
 5 
 6 M.i = {r = 0, i = 1}
 7 
 8 function M.new(r, i)
 9     return {r=r, i=i}
10 end
11 
12 function M.add(c1, c2)
13     return M.new(c1.r + c2.r, c1.i + c2.i)
14 end
15 
16 ...

另外一个改进是不需要return 模块名字了。因为,如果一个模块没有返回值的话,require就会返回package.loaded[modname]的当前值。

 

  现在的创建模块的基本方法缺点在于:在访问同一模块的其他方法时候,必须限定名称。通过使用"函数环境"这种技术,可以解决这个问题。

 1 local modname = ...
 2 local M = {}
 3 _G[modname] = M
 4 package.loaded[modname] = M
 5 setfenv(1, M)
 6 
 7 function M.new(r, i) return {r=r, i=i} end
 8 
 9 function add(c1, c2)
10     return new(c1.r + c2.r, c1.i + c2.i)
11 end
12 
13 ...

这里add函数就从环境中得到new也就是complex.new。但是由于使用了环境,会导致访问其他模块出现问题。比如访问全局模块_G。

 

  一般较好的解决办法是将需要用到的模块声明为局部变量:

  

 1 local modname = ...
 2 local M = {}
 3 _G[modname] = M
 4 package.loaded[modname] = M
 5 
 6 -- 导入
 7 local sqrt = math.sqrt
 8 local io = io
 9 
10 setfenv(1, M)

 

  在Lua5.1后,Lua提供了一个新函数modle,包括了:

 

1 local modname = ...
2 
3 local M = {}
4 
5 _G[modname] = M
6 
7 package.loaded[modname] = M
8 
9 setfenv(1, M)

这些功能。默认情况下,module不提供对外访问。必须在调用它之前,为所需要访问的外部函数或者模块声明恰当的局部变量。也可以通过继承来实现外部访问。只需要在module时候加一个选项package.seeall。这个选项等价于以下代码:

setmetatable(M, {__index = _G}),只需要这么做:module(..., package.seeall)

 

转载于:https://www.cnblogs.com/david-wang/p/4357298.html

相关文章:

  • Linux下Mongodb数据库日志切割及定时删除
  • 数据库加锁操作
  • Scala.js:将Scala编译为JavaScript的编译器
  • 如果你写PHP, 请多注意自己是否有良好的习惯
  • django数据模型字段和通用参数说明
  • 微软职位内部推荐-Software Development Engineer 2
  • Java JNI介绍
  • linux ubuntu ElasticSearch 安装 基本使用
  • iTunesU无法上传,决定放弃
  • Netty线程模型详解
  • 联想昭阳e43l笔记本配置
  • jquery 绘图工具 flot 学习笔记
  • 正则表达式之egrep实战示例
  • Java多线程编程(5)-volatile和synchronized比较
  • 如何将数据库账号(用户)解锁
  • [分享]iOS开发 - 实现UITableView Plain SectionView和table不停留一起滑动
  • [译]Python中的类属性与实例属性的区别
  • Cumulo 的 ClojureScript 模块已经成型
  • Javascript设计模式学习之Observer(观察者)模式
  • js中forEach回调同异步问题
  • linux学习笔记
  • Lucene解析 - 基本概念
  • MySQL用户中的%到底包不包括localhost?
  • PermissionScope Swift4 兼容问题
  • spark本地环境的搭建到运行第一个spark程序
  • SpringBoot几种定时任务的实现方式
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • Vue学习第二天
  • webpack4 一点通
  • Web标准制定过程
  • yii2权限控制rbac之rule详细讲解
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 创建一种深思熟虑的文化
  • 从setTimeout-setInterval看JS线程
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 前端存储 - localStorage
  • 前嗅ForeSpider教程:创建模板
  • 如何打造100亿SDK累计覆盖量的大数据系统
  • 基于django的视频点播网站开发-step3-注册登录功能 ...
  • 继 XDL 之后,阿里妈妈开源大规模分布式图表征学习框架 Euler ...
  • ​Linux·i2c驱动架构​
  • ​决定德拉瓦州地区版图的关键历史事件
  • #我与Java虚拟机的故事#连载14:挑战高薪面试必看
  • $GOPATH/go.mod exists but should not goland
  • %@ page import=%的用法
  • (1)(1.11) SiK Radio v2(一)
  • (windows2012共享文件夹和防火墙设置
  • (zt)基于Facebook和Flash平台的应用架构解析
  • (附源码)springboot 房产中介系统 毕业设计 312341
  • (三) prometheus + grafana + alertmanager 配置Redis监控
  • (十五)使用Nexus创建Maven私服
  • (转)C#开发微信门户及应用(1)--开始使用微信接口
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)linux自定义开机启动服务和chkconfig使用方法
  • (转)socket Aio demo