第一版为 Lua 5.0 编写。虽然在很大程度上仍然适用于后续版本,但有一些差异。
第四版针对 Lua 5.3,可在 Amazon 和其他书店购买。
购买本书,您还将帮助支持 Lua 项目


15.1 – 基本方法

定义包的一种简单方法是将包名称作为包中每个对象的名称前缀。例如,假设我们正在编写一个库来处理复数。我们将每个复数表示为一个表,其中包含字段 r(实部)和 i(虚部)。我们在另一个表中声明所有新操作,该表充当新包

    complex = {}
    
    function complex.new (r, i) return {r=r, i=i} end
    
    -- defines a constant `i'
    complex.i = complex.new(0, 1)
    
    function complex.add (c1, c2)
      return complex.new(c1.r + c2.r, c1.i + c2.i)
    end
    
    function complex.sub (c1, c2)
      return complex.new(c1.r - c2.r, c1.i - c2.i)
    end
    
    function complex.mul (c1, c2)
      return complex.new(c1.r*c2.r - c1.i*c2.i,
                         c1.r*c2.i + c1.i*c2.r)
    end
    
    function complex.inv (c)
      local n = c.r^2 + c.i^2
      return complex.new(c.r/n, -c.i/n)
    end
    
    return complex
此库定义了一个全局名称,complex。所有其他定义都位于此表中。

使用此定义,我们可以使用任何复数操作来限定操作名称,如下所示

    c = complex.add(complex.i, complex.new(10, 20))

使用表作为包并不能提供与真实包完全相同的功能。首先,我们必须在每个函数定义中明确放置包名称。其次,在同一包中调用另一个函数的函数必须限定被调用函数的名称。我们可以使用包的固定局部名称(例如 P)来改善这些问题,然后将此局部名称分配给包的最终名称。按照此准则,我们将编写如下之前的定义

    local P = {}
    complex = P           -- package name
    
    P.i = {r=0, i=1}
    function P.new (r, i) return {r=r, i=i} end
    
    function P.add (c1, c2)
      return P.new(c1.r + c2.r, c1.i + c2.i)
    end
    
       ...
每当函数在同一包中调用另一个函数(或每当它自己递归调用时),它仍然需要添加名称前缀。至少,两个函数之间的连接不再依赖于包名称。此外,在整个包中只有一个地方可以编写包名称。

您可能注意到包中的最后一条语句是

    return complex
此返回不是必需的,因为包已分配给全局变量(complex)。不过,我们认为包在打开时返回自身是一种好习惯。额外的返回没有任何成本,并允许以其他方式处理包。