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


17.1 – 备忘函数

一种常见的编程技术是用空间换取时间。您可以通过备忘函数的结果来加速某些函数,以便以后使用相同参数调用函数时,它可以重复使用结果。

想象一下一个通用服务器,它接收包含 Lua 代码的字符串的请求。每次收到请求时,它都会对字符串运行 loadstring,然后调用结果函数。但是,loadstring 是一个昂贵的函数,并且对服务器的某些命令可能非常频繁。服务器可以备忘 loadstring 的结果,使用辅助表,而不是在每次接收到诸如 "closeconnection()" 的通用命令时都反复调用 loadstring。在调用 loadstring 之前,服务器会在表中检查该字符串是否已翻译。如果找不到字符串,则(且仅当)服务器调用 loadstring 并将结果存储到表中。我们可以将此行为打包到一个新函数中

    local results = {}
    function mem_loadstring (s)
      if results[s] then      -- result available?
        return results[s]     -- reuse it
      else
        local res = loadstring(s)   -- compute new result
        results[s] = res            -- save for later reuse
        return res
      end
    end

此方案节省的开销可能很大。但是,它也可能造成意想不到的浪费。虽然一些命令会反复执行,但许多其他命令只执行一次。结果表 results 会逐渐累积服务器接收过的所有命令及其各自的代码;一段时间后,这会耗尽服务器的内存。弱表为这个问题提供了一个简单的解决方案。如果 results 表具有弱值,则每个垃圾回收周期都会删除所有在该时刻未使用的翻译(这意味着几乎所有翻译)。

    local results = {}
    setmetatable(results, {__mode = "v"})  -- make values weak
    function mem_loadstring (s)
       ...    -- as before
实际上,由于索引始终是字符串,如果需要,我们可以使该表完全弱。
    setmetatable(results, {__mode = "kv"})
最终结果完全相同。

备忘技术还可用于确保某种对象的唯一性。例如,假设一个系统将颜色表示为表,其中字段 redgreenblue 处于某个范围内。一个天真的颜色工厂为每个新请求生成一个新颜色

    function createRGB (r, g, b)
      return {red = r, green = g, blue = b}
    end
使用记忆技术,我们可以对相同的颜色重复使用相同的表。要为每种颜色创建一个唯一键,我们只需将颜色索引与中间的分隔符连接起来
    local results = {}
    setmetatable(results, {__mode = "v"})  -- make values weak
    function createRGB (r, g, b)
      local key = r .. "-" .. g .. "-" .. b
      if results[key] then return results[key]
      else
        local newcolor = {red = r, green = g, blue = b}
        results[key] = newcolor
        return newcolor
      end
    end
这种实现的一个有趣后果是用户可以使用原始相等运算符比较颜色,因为两个共存的相等颜色始终由同一张表表示。请注意,同一颜色可能在不同时间由不同的表表示,因为垃圾回收周期会时不时地清除 results 表。但是,只要给定颜色正在使用,它就不会从 results 中删除。因此,只要一种颜色存活足够长的时间与一种新颜色进行比较,它的表示形式也存活足够长的时间以供新颜色重复使用。