通常, Lua
语言不会设置规则。相反, Lua
语言提供的是足够强大的机制供不同的开发者实现最适合自己的规则。当然,这种方法对于模块而言并不是特别使用。模块系统的主要目标之一就是允许不同的人共享代码,缺乏公共规则就无法实现这样的共享。
Lua
语言从 5.1
版本开始为模块和包(模块的集合)定义了一系列的规则。这些规则不需要从语言中引入额外的功能,程序员可以使用目前为止我们学习到的机制实现这些规则。程序员也可以自由地使用不同的策略。当然,不同的实现可能会导致程序不能使用外部模块,或者模块不能被外部程序使用。
从用户观点来看,一个模块就是一些代码(要么是 Lua
语言编写的,要么是 C
语言编写的),这些代码可以通过函数 require
加载,然后创建和返回一个表。这个表就像是某种命名空间,其中定义的内容是模块中导出的东西,比如函数和常量。
例如,所有的标准库都是模块。我们可以按照下列的方法使用数学库:
local m = require "math" print(m.sin(3.14))
独立解释器会使用跟如下代码等价的方式提前加载所有标准库:
math = require "math" string = require "string" ...
这种提前加载使得我们可以不用费劲德编写代码来加载模块 math
就可以直接使用函数 math.sin
。
使用表来实现模块的显著优点之一是,让我们可以像操作普通表那样操作模块,并且能利用 Lua
语言的所有功能实现额外的功能。在大多数语言中,模块不是第一类值(即他们不能被保存在变量中,也不能被当做参数传递给函数等),所以这些语言需要为模块实现一些专门的机制。而 Lua
语言中,我们则可以轻易地实现这些功能。
例如,用户调用模块中的函数就有几种方法,其中常见的方法是:
local mod = require "mod" mod.foo()
用户可以为模块设置一个局部名称:
local m = require "mod" m.foo()
也可以为个别函数提供不同的名称:
local m = require "mod" local f = m.foo f()
还可以只引入特定的函数:
local f = require "mod".foo -- (require("mod")).foo f()
上述这些方法的好处是无需语言的特别支持,他们使用的都是语言已经提供的功能。