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


15.2 – 隐私

有时,一个包会导出其所有名称;也就是说,该包的任何客户端都可以使用它们。然而,通常情况下,在一个包中拥有私有名称很有用,也就是说,只有该包本身才能使用的名称。在 Lua 中,一种方便的方法是将这些私有名称定义为局部变量。例如,让我们向我们的示例中添加一个私有函数,用于检查一个值是否是有效的复数。我们的示例现在看起来像这样

    local P = {}
    complex = P
    
    local function checkComplex (c)
      if not ((type(c) == "table") and
         tonumber(c.r) and tonumber(c.i)) then
        error("bad complex number", 3)
      end
    end
    
    function P.add (c1, c2)
      checkComplex(c1);
      checkComplex(c2);
      return P.new(c1.r + c2.r, c1.i + c2.i)
    end
    
      ...
    
    return P

这种方法的优点和缺点是什么?一个包中的所有名称都存在于一个单独的名称空间中。包中的每个实体都明确标记为公共或私有。此外,我们拥有真正的隐私:私有实体在包外不可访问。这种方法的一个缺点是,在同一个包内访问其他公共实体时,它很冗长,因为每次访问仍然需要前缀P。一个更大的问题是,每当我们将函数的状态从私有更改为公共(或从公共更改为私有)时,我们都必须更改调用。

有一个有趣的解决方案可以同时解决这两个问题。我们可以将包中所有函数声明为局部函数,然后将它们放入要导出的最终表中。按照这种方法,我们的complex包将如下所示

    local function checkComplex (c)
      if not ((type(c) == "table")
         and tonumber(c.r) and tonumber(c.i)) then
        error("bad complex number", 3)
      end
    end
    
    local function new (r, i) return {r=r, i=i} end
    
    local function add (c1, c2)
      checkComplex(c1);
      checkComplex(c2);
      return new(c1.r + c2.r, c1.i + c2.i)
    end
    
      ...
    
    complex = {
      new = new,
      add = add,
      sub = sub,
      mul = mul,
      div = div,
    }

现在,我们不需要对任何调用添加前缀,因此对导出函数和私有函数的调用是相等的。包的末尾有一个简单的列表,明确定义了要导出的名称。大多数人觉得将此列表放在包的开头更自然,但我们无法将列表放在顶部,因为我们必须首先定义局部函数。