雷林鹏分享:Lua 模块与包

  模块类似于一个封装库,从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。

  Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行。以下为创建自定义模块 module.lua,文件代码格式如下:

  -- 文件名为 module.lua

  -- 定义一个名为 module 的模块

  module = {}

  -- 定义一个常量

  module.constant = "这是一个常量"

  -- 定义一个函数

  function module.func1()

  io.write("这是一个公有函数!\n")

  end

  local function func2()

  print("这是一个私有函数!")

  end

  function module.func3()

  func2()

  end

  return module

  由上可知,模块的结构就是一个 table 的结构,因此可以像操作调用 table 里的元素那样来操作调用模块里的常量或函数。

  上面的 func2 声明为程序块的局部变量,即表示一个私有函数,因此是不能从外部访问模块里的这个私有函数,必须通过模块里的公有函数来调用.

  require 函数

  Lua提供了一个名为require的函数用来加载模块。要加载一个模块,只需要简单地调用就可以了。例如:

  require("<模块名>")

  或者

  require "<模块名>"

  执行 require 后会返回一个由模块常量或函数组成的 table,并且还会定义一个包含该 table 的全局变量。

  -- test_module.lua 文件

  -- module 模块为上文提到到 module.lua

  require("module")

  print(module.constant)

  module.func3()

  以上代码执行结果为:

  这是一个常量

  这是一个私有函数!

  或者给加载的模块定义一个别名变量,方便调用:

  -- test_module2.lua 文件

  -- module 模块为上文提到到 module.lua

  -- 别名变量 m

  local m = require("module")

  print(m.constant)

  m.func3()

  以上代码执行结果为:

  这是一个常量

  这是一个私有函数!

  加载机制

  对于自定义的模块,模块文件不是放在哪个文件目录都行,函数 require 有它自己的文件路径加载策略,它会尝试从 Lua 文件或 C 程序库中加载模块。

  require 用于搜索 Lua 文件的路径是存放在全局变量 package.path 中,当 Lua 启动后,会以环境变量 LUA_PATH 的值来初始这个环境变量。如果没有找到该环境变量,则使用一个编译时定义的默认路径来初始化。

  当然,如果没有 LUA_PATH 这个环境变量,也可以自定义设置,在当前用户根目录下打开 .profile 文件(没有则创建,打开 .bashrc 文件也可以),例如把 "~/lua/" 路径加入 LUA_PATH 环境变量里:

  #LUA_PATH

  export LUA_PATH="~/lua/?.lua;;"

  文件路径以 ";" 号分隔,最后的 2 个 ";;" 表示新加的路径后面加上原来的默认路径。

  接着,更新环境变量参数,使之立即生效。

  source ~/.profile

  这时假设 package.path 的值是:

  /Users/dengjoe/lua/?.lua;./?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/lib/lua/5.1/?.lua;/usr/local/lib/lua/5.1/?/init.lua

  那么调用 require("module") 时就会尝试打开以下文件目录去搜索目标。

  /Users/dengjoe/lua/module.lua;

  ./module.lua

  /usr/local/share/lua/5.1/module.lua

  /usr/local/share/lua/5.1/module/init.lua

  /usr/local/lib/lua/5.1/module.lua

  /usr/local/lib/lua/5.1/module/init.lua

  如果找过目标文件,则会调用 package.loadfile 来加载模块。否则,就会去找 C 程序库。

  搜索的文件路径是从全局变量 package.cpath 获取,而这个变量则是通过环境变量 LUA_CPATH 来初始。

  搜索的策略跟上面的一样,只不过现在换成搜索的是 so 或 dll 类型的文件。如果找得到,那么 require 就会通过 package.loadlib 来加载它。

  C 包

  Lua和C是很容易结合的,使用C为Lua写包。

  与Lua中写包不同,C包在使用以前必须首先加载并连接,在大多数系统中最容易的实现方式是通过动态连接库机制。

  Lua在一个叫loadlib的函数内提供了所有的动态连接的功能。这个函数有两个参数:库的绝对路径和初始化函数。所以典型的调用的例子如下:

  local path = "/usr/local/lua/lib/libluasocket.so"

  local f = loadlib(path, "luaopen_socket")

  loadlib函数加载指定的库并且连接到Lua,然而它并不打开库(也就是说没有调用初始化函数),反之他返回初始化函数作为Lua的一个函数,这样我们就可以直接在Lua中调用他。

  如果加载动态库或者查找初始化函数时出错,loadlib将返回nil和错误信息。我们可以修改前面一段代码,使其检测错误然后调用初始化函数:

  local path = "/usr/local/lua/lib/libluasocket.so"

  -- 或者 path = "C:\\windows\\luasocket.dll",这是 Window 平台下

  local f = assert(loadlib(path, "luaopen_socket"))

  f() -- 真正打开库

  一般情况下我们期望二进制的发布库包含一个与前面代码段相似的stub文件,安装二进制库的时候可以随便放在某个目录,只需要修改stub文件对应二进制库的实际路径即可。

  将stub文件所在的目录加入到LUA_PATH,这样设定后就可以使用require函数加载C库了。

  点击查看所有 Lua 教程 文章: https://www.codercto.com/courses/l/21.html(编辑:雷林鹏 来源:网络 侵删)

原文地址:https://www.cnblogs.com/pengpeng1208/p/11126487.html

时间: 2024-08-29 06:58:24

雷林鹏分享:Lua 模块与包的相关文章

雷林鹏分享:Ruby 模块(Module)

Ruby 模块(Module) 模块(Module)是一种把方法.类和常量组合在一起的方式.模块(Module)为您提供了两大好处. 模块提供了一个命名空间和避免名字冲突. 模块实现了 mixin 装置. 模块(Module)定义了一个命名空间,相当于一个沙箱,在里边您的方法和常量不会与其他地方的方法常量冲突. 语法 module Identifier statement1 statement2 ........... end 模块常量命名与类常量命名类似,以大写字母开头.方法定义看起来也相似:

雷林鹏分享:Lua 迭代器

迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址 在Lua中迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素. 泛型 for 迭代器 泛型 for 在自己内部保存迭代函数,实际上它保存三个值:迭代函数.状态常量.控制变量. 泛型 for 迭代器提供了集合的 key/value 对,语法格式如下: for k, v in pairs(t) do print(k, v) end 上面代码中,k, v为变量列表;pai

雷林鹏分享:Lua 协同程序(coroutine)

什么是协同(coroutine)? Lua 协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西. 协同是非常强大的功能,但是用起来也很复杂. 线程和协同程序区别 线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行. 在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起. 协同程序有点类似同步的多线程,在

雷林鹏分享:Flask开发环境安装配置

安装Flask通常需要Python 2.6或更高版本. 尽管Flask及其依赖与Python 3(Python 3.3以上版本)配合良好,但许多Flask扩展并不能正确支持它. 因此,但是官方建议在Python 3.6+ 以上安装Flask. 安装virtualenv virtualenv是一个虚拟的Python环境构建器. 它可以帮助用户并行创建多个Python环境. 因此,它可以避免不同版本的库之间的兼容性问题. 使用虚拟环境在开发和生产中管理项目的依赖关系. 虚拟环境解决什么问题? 您拥有

雷林鹏分享:Ruby JSON

Ruby JSON 本章节我们将为大家介绍如何使用 Ruby 语言来编码和解码 JSON 对象. 环境配置 在使用 Ruby 编码或解码 JSON 数据前,我们需要先安装 Ruby JSON 模块.在安装该模块前你需要先安装 Ruby gem,我们使用 Ruby gem 安装 JSON 模块. 但是,如果你使用的是最新版本的 Ruby,可能已经安装了 gem,解析来我们就可以使用以下命令来安装Ruby JSON 模块: $gem install json 使用 Ruby 解析 JSON 以下为J

雷林鹏分享:Ruby 异常

Ruby 异常 异常和执行总是被联系在一起.如果您打开一个不存在的文件,且没有恰当地处理这种情况,那么您的程序则被认为是低质量的. 如果异常发生,则程序停止.异常用于处理各种类型的错误,这些错误可能在程序执行期间发生,所以要采取适当的行动,而不至于让程序完全停止. Ruby 提供了一个完美的处理异常的机制.我们可以在 begin/end 块中附上可能抛出异常的代码,并使用 rescue 子句告诉 Ruby 完美要处理的异常类型. 语法 begin # - rescue OneTypeOfExce

雷林鹏分享:Ruby 面向对象

Ruby 面向对象 Ruby 是纯面向对象的语言,Ruby 中的一切都是以对象的形式出现.Ruby 中的每个值都是一个对象,即使是最原始的东西:字符串.数字,甚至连 true 和 false 都是对象.类本身也是一个对象,是 Class 类的一个实例.本章将向您讲解所有与 Ruby 面向对象相关的主要功能. 类用于指定对象的形式,它结合了数据表示法和方法,把数据整理成一个整齐的包.类中的数据和方法被称为类的成员. Ruby 类定义 当您定义一个类时,您实际是定义了一个数据类型的蓝图.这实际上并没

雷林鹏分享:Ruby 文件的输入与输出

Ruby 文件的输入与输出 Ruby 提供了一整套 I/O 相关的方法,在内核(Kernel)模块中实现.所有的 I/O 方法派生自 IO 类. 类 IO 提供了所有基础的方法,比如 read. write. gets. puts. readline. getc 和 printf. 本章节将讲解所有 Ruby 中可用的基础的 I/O 函数.如需了解更多的函数,请查看 Ruby 的 IO 类. puts 语句 在前面的章节中,您赋值给变量,然后使用 puts 语句打印输出. puts 语句指示程序

雷林鹏分享:linux环境下安装PHP Yaf框架

在 Linux 系统下安装YAF 要求: PHP 5.2+ 下载Yaf的最新版本, 解压缩以后, 进入Yaf的源码目录, 依次执行(其中PHP_BIN是PHP的bin目录): 最新版YAF下载地址: https://github.com/laruence/php-yaf 编译Yaf: $PHP_BIN/phpize ./configure --with-php-config=$PHP_BIN/php-config make make install 然后在php.ini中载入yaf.so, 重启