lua学习笔记之模块、包

模块需要通过函数require来加载,创建返回表。模块导出的所有如函数、常量作为一个工作空间。

1、require函数

require首先检查表package.loaded是否模块已经加载,如果已经加载,则返回对应的值。如果模块没有加载,require搜索模块名字对应的lua文件,搜索通过package.path来引导,如果找到文件,则使用loadfile加载,返回的结果是称为加载器的函数。如果没有找到模块名对应的lua文件,则搜索对应名字的c库文件,此时搜索是通过package.cpath变量来引导,如果找到,则使用package.loadlib,来查找称为luaopen_modname对应的函数。

1.1 模块重命名

对于多版本,可以使用mod-版本号。因为require在加载时是只取-号前的。

1.2、路径搜索

require使用的路径是一系列的模板,路径的模板是包含可选的问号标识的文件名,模板间使用分号相隔。

lua文件的搜索路径通过package.path变量指定。当模块包初始化时,变量名是通过LUA_PATH_5_3环境变量来设置,如果环境变量没有定义,使用环境变量LUA_PATH,如果两个都没有定义,使用编译定义的默认路径 。

c文件的搜索路径通过package.cpath变量指定。通过环境变量LUA_CPATH_5_3或者LUA_CPATH环境变量来指定。

1.3 搜索器

搜索lua文件和搜索c库仅仅是搜索器的两个实例。搜索器是一个函数,携带模块名,返回 模块的加载器或者nil.

数组package.searchers包含了require使用的搜索器。当搜索模块时,require调用每个搜索器来搜索模块名直到其中的一个找到模块的加载器。如果没有找到,require抛出错误。

默认配置中,搜索lua文件和搜索c库的搜索器分别位于列表中的第2个,第3个。在它们之前,是一个preload搜索器。

preload搜索器允许任意加载模块的函数定义。使用称为package.preload的表来映射模块名到加载函数。当搜索模块名时,搜索器在表中查找给定的名字,如果找到函数,则返回函数作为模块加载器,否则返回nil。搜索器提供了通用方法来处理一些非传统的情况,比如,静态链接到lua的c库可以注册它的luaopen函数到preload表中,以便当用户需要那个模块时可以被 调用 。

package.searchers的默认内容包含第四个函数,与子模块相关。

2、模块的基本写法

创建一个表,将所有需要导出的函数放入表中,并且返回这个表。

local M = {}

local function new(r, i)
    return {r = r, i = i}
end

M.new = new

M.i = new(0, 1)

function M.add(c1, c2)
    return new(c1.r + c2.r, c1.i + c2.i)
end

function M.sub(c1, c2)
    return new(c1.r - c2.r, c1.i - c2.i)
end

function M.mul(c1, c2)
    return new(c1.r * c2.r - c1.i * c2.i, c1.r * c2.i + c1.i * c2.r)
end

local function inv(c)
    local n = c.r^2 + c.i^2
    return new(c.r / n, -c.i / n)
end

function M.div(c1, c2)
    return M.mul(c1, inv(c2))
end

function M.toString(c)
    return string.format("(%g, %g)", c.r, c.i)
end

return M

另外一种写法如下

local M = {}

一些定义,最后加上

package.loaded[...] = M

第三种形式是先定义函数为本地函数,然后返回表

lua学习笔记之模块、包_第1张图片

3、子模块和包

lua允许模块有层级关系,通过使用点来分离名字层级。

当使用require函数加载子模块时,首先查找package.loaded表,然后查找package.preload表,但是当搜索子模块的文件时,会将点翻译成系统的目录分隔符。

lua使用的目录分隔符是在编译时配置的,可以是任意字符串。对于没有层级目录的系统可以使用下划线来表示目录分隔符。

对于子模块的c库,require会将点翻译成下线线。比如a.b的初始化函数为luaopen_a_b

你可能感兴趣的:(lua,lua,开发语言)