Chapter 15_0 模块和包

时间:2021-05-26 17:30:50

  通常,Lua不会设置规则,相反会提供很多强有力的机制来使开发者有能力实现出最适应的规则。

然而,这种方法对于模块就不行了。模块系统的一个主要目标是允许以不同的形式来共享代码。

但若没有一项公共的规则就无法实现这样的共享。

  从Lua5.1版本开始,就为模块和包定义了一系列的规则。不统一的实现可能会使程序无法使用外部模块,或者编写的模块无法被外部程序使用。

从用户观点来看,一个模块就是一些用Lua或C实现的代码,通过require去加载并返回一个table。

比如,所有的标准库就是模块。就像下面的数学库:

local m = require "math"
print(m.sin(3.14))

解释器会用类似下面的代码预加载所有的标准库:

math = require "math"
string = require "sting"
...

有了这样的预加载,我们才可以使用类似math.sin这样的语法。

一个用户要调用一个模块中的函数,其中最简单的方法是:

local mod = require "mod"
mod.foo()

用户可以为这个模块命名为任何的局部名字:

loacl m  = require "mod"
m.foo()

也可以为模块中独特的函数命名:

local m = require "mod"
local f = mod.foo
f()

上述这些方法,都不需要来自于语言的显式支持,只需要使用语言现有的内容。

有一个抱怨require的普遍现象,就是它在加载模块是不能传参。比如数学库里有两个不同的选项(degree 和radians),想通过下面的代码去实现degree就不行:

--bad code
local math = require("math", "degree")

导致这个问题的原因是 require的主要目的是避免多次加载模块。不同参数去调用require会导致冲突。

如果真的想传参,可以创建一个函数去实现它:

local mod = require "mod"
mod.init(, )

当初始化函数返回模块本身的话,我们可以这样去写代码:

local mod = require "mod".init(,)

另一个选择是,让模块返回初始化函数,并且只有这个函数会返回该模块的table。

无论如何,请记住模块至始至终都只加载一次。

以上内容来自:《Lua程序设计第二版》和《Programming in Lua  third edition 》