解析Lua中的全局环境、包、模块组织结构

 更新时间:2016年06月17日 15:52:12   作者:林寿山  
Lua中也拥有和Python世界相似的代码的作用范围和组织方式,下面我们就来简单解析Lua中的全局环境、包、模块组织结构,需要的朋友可以参考下
(福利推荐:【腾讯云】服务器最新限时优惠活动,云服务器1核2G仅99元/年、2核4G仅768元/3年,立即抢购>>>:9i0i.cn/qcloud

(福利推荐:你还在原价购买阿里云服务器?现在阿里云0.8折限时抢购活动来啦!4核8G企业云服务器仅2998元/3年,立即抢购>>>:9i0i.cn/aliyun

模块就是一个程序库,而包是一系列模块。Lua中可以通过require来加载模块,然后得到一个全局变量表示一个table。Lua将其所有的全局变量保存在一个被称为“环境”的常规table中。本文首先介绍环境的一些实用技术,然后介绍如何引用模块及编写模块的基本方法。

1. 环境
Lua将环境table保存在一个全局变量_G中,可以对其访问和设置。有时我们想操作一个全局变量,而它的名称却存储在另一个变量中,或者需要通过运行时的计算才能得到,可以通过value = _G[varname]来获得动态名字的全局变量。

关于“环境”的一大问题是它是全局的,任何对它的修改都会影响程序的所有部分。Lua 5允许每个函数拥有一个子集的环境来查找全局变量,可以通过setfenv来改变一个函数的环境,第一个参数若是1则表示当前函数,2则表示调用当前函数的函数(依次类推),第二个参数是一个新的环境table。

a = 1
setfenv(1, {})
print(a) -- 会报错,print是一个nil。这是因为一旦改变环境,所有的全局访问都会使用新的table

为了避免上述问题,可以使用setfenv(1, {_G = _G})将原来的环境保存起来,然后用_G.print来引用。另一种组装新环境的方法是使用继承,下面的代码新环境从源环境中继承了print和a,任何赋值都发生在新的table中。

a = 1
local newgt = {}
setmetatable(newgt, {__index = _G})
setfenv(1, newgt)
print(a)

2. 模块与包
2.1 调用模块

要调用模块mod中的foo方法,可以用require函数来加载,如:

require "mod"
mod.foo()
-- 或者
local m = require "mod"
m.foo()

require函数的行为: (关于require使用的路径查找策略不赘述)
在package.loaded这个table中检查模块是否已加载
=> 已加载,就返回相应的值(可见一个模块只会加载一次)
=> 未加载,就试着在package.preload中查询传入的模块名
===> 找到一个函数,就以该函数作为模块的加载器
===> 找不到,则尝试从Lua文件或C程序库中加载模块
=====> 找到Lua文件,通过loadfile来加载文件
=====> 找到C程序库,通过loadlib来加载文件

2.2 使用环境

下面的代码说明了如何用环境来创建一个复数(complex)模块:

-- 模块设置
local modname = "complex"
local M = {}
_G[modname] = M
package.loaded[modname] = M

-- 声明模块从外界所需的所有东西
local _G = _G -- 保留旧环境的引用,使用时需要像_G.print这样用
local io = io

-- 运行这句之后环境就变了
setfenv(1, M)

function 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时,就成为了complex.add,调用同一模块的其他函数也不需要加前缀。

2.3 module函数

Lua 5.1提供了一个新函数module,囊括了上面一系列定义环境的功能。在开始编写一个模块时,可以直接用module("modname", package.seeall)来取代前面的设置代码。在一个模块文件开头有这句调用后,后续所有代码都不需要限定模块名和外部名字,同样也不需要返回模块table了。

2.4 子模块与包

Lua支持具有层级的模块名,用一个点来分隔名称中的层级。例如一个模块名为mod.sub,就是mod的一个子模块。一个包(package)就是一个完整的模块树,它是Lua中发型的单位。注意,当搜索一个子模块文件时,require会把点号当做目录分隔符来搜索,也就是说调用require "a.b"会尝试打开./a/b.lua,/usr/local/lua/a/b.lua,/usr/local/lua/a/b/init.lua。通过这种加载策略,可以将包的所有模块组织到一个目录中。

2.5 以自定义方式加载 lua 模块
从 Lua 5.1 以后,Lua 有了标准的模块管理库。所以所有的模块加载都是通过 require 来完成。 require 的设计是颇具扩展性的,它会从若干个定义好的 loader 中逐个尝试加载新的模块。系统库中提供了四个 loader ,分别实现已加载模块,Lua 模块,和 C 扩展模块(用了两个 loader 来实现 C 扩展模块的加载)。这些 loader 以 CFunction 的形式放在 require 的环境中的一个 table 里。

如果我们想改变 lua 模块的加载形式,只需要替换或增加一个新的 loader 就可以了。

要做的只需要模仿 loadlib.c 中的 loader_Lua 函数做一个自己的实现,比如在我们的项目中,就允许从自定义格式数据包中,加载一个被加密过的 Lua 代码文件。然后写几行 C 代码,获得 require 的环境(使用 lua_getfenv ),然后取出其中 "loaders" 这个 table ,把新的自定义 loader 插入到 index 2 的地方。

具体的代码就不详述了,仔细阅读一下 ll_require 的实现(在 loadlib.c 中)就很容易明白。我们的整个工作从分析到实现没有超过两个小时,这真是得益于 Lua 良好的设计啊 :D 甚至如果你想从一个网络连接的数据流中加载 Lua 模块,或是通过 http/ftp 协议下载,也是行的通的吧。

相关文章

  • Lua math.fmod使用时的小数问题

    Lua math.fmod使用时的小数问题

    这篇文章主要介绍了Lua math.fmod使用时的小数问题,math.fmod用于取模运算,使用小数时可能会遇到不可预料的结果,所以应该避免使用小数,需要的朋友可以参考下
    2015-06-06
  • Lua中的基本语法、控制语句总结

    Lua中的基本语法、控制语句总结

    这篇文章主要介绍了Lua中的基本语法、控制语句总结,本文总结了赋值、局部变量与块、控制结构、数字型for、泛型for等内容,需要的朋友可以参考下
    2014-09-09
  • Lua教程(一):在C++中嵌入Lua脚本

    Lua教程(一):在C++中嵌入Lua脚本

    这篇文章主要介绍了Lua教程(一):在C++中嵌入Lua脚本,本文在MAC环境中开发,同时探讨了IOS项目集成Lua、Android项目集成Lua等内容,需要的朋友可以参考下
    2014-09-09
  • Lua table的concat方法使用实例

    Lua table的concat方法使用实例

    这篇文章主要介绍了Lua table的concat方法使用实例,本文讲解了concat方法的用法及使用实例,需要的朋友可以参考下
    2015-04-04
  • Lua中table的一些辅助函数介绍

    Lua中table的一些辅助函数介绍

    这篇文章主要介绍了Lua中table的一些辅助函数介绍,这些函数组成了table的函数库,需要的朋友可以参考下
    2014-09-09
  • 简单谈谈lua和c的交互

    简单谈谈lua和c的交互

    要理解Lua和C++交互,首先要理解Lua堆栈。简单来说,Lua和C/C++语言通信的主要方法是一个无处不在的虚拟栈。栈的特点是先进后出。
    2016-01-01
  • 使用Lua作为C语言项目的配置文件实例

    使用Lua作为C语言项目的配置文件实例

    这篇文章主要介绍了使用Lua作为C语言项目的配置文件实例,本文用Lua创建了一个配置文件,然后在C言语中解析它,需要的朋友可以参考下
    2015-04-04
  • lua 基础教程

    lua 基础教程

    Lua 的语法比较简单,学习起来也比较省力,但功能却并不弱。所以,我只简单的归纳一下Lua的一些语法规则,使用起来方便好查就可以了。估计看完了,就懂得怎么写Lua程序了。
    2015-09-09
  • Lua教程(二):语法约定

    Lua教程(二):语法约定

    这篇文章主要介绍了Lua教程(二):语法约定,本文讲解了lua保留关键字、使用的标点符号、字符串、ASCII 码等,需要的朋友可以参考下
    2015-03-03
  • Lua中的变量类型与语句学习总结

    Lua中的变量类型与语句学习总结

    这篇文章主要介绍了Lua中的变量类型与语句学习总结,总结了Lua入门过程中的一些基础知识,需要的朋友可以参考下
    2016-06-06

最新评论

?


http://www.vxiaotou.com