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


10.1 – 数据描述

Lua 网站保留了一个数据库,其中包含使用 Lua 的全球项目示例。我们以自动记录的方式通过构造函数在数据库中表示每个条目,如下例所示

    entry{
      title = "Tecgraf",
      org = "Computer Graphics Technology Group, PUC-Rio",
      url = "http://www.tecgraf.puc-rio.br/",
      contact = "Waldemar Celes",
      description = [[
        TeCGraf is the result of a partnership between PUC-Rio,
        the Pontifical Catholic University of Rio de Janeiro,
        and <A HREF="http://www.petrobras.com.br/">PETROBRAS</A>,
        the Brazilian Oil Company.
        TeCGraf is Lua's birthplace,
        and the language has been used there since 1993.
        Currently, more than thirty programmers in TeCGraf use
        Lua regularly; they have written more than two hundred
        thousand lines of code, distributed among dozens of
        final products.]]
      }
这种表示的有趣之处在于,包含此类条目序列的文件是一个 Lua 程序,它使用表作为调用参数对函数 entry 进行一系列调用。

我们的目标是编写一个程序,以 HTML 格式显示该数据,以便它成为网页 https://lua.ac.cn/uses.html。由于有许多项目,最终页面首先显示所有项目标题的列表,然后显示每个项目的详细信息。程序的结果类似于这样

    <HTML>
    <HEAD><TITLE>Projects using Lua</TITLE></HEAD>
    <BODY BGCOLOR="#FFFFFF">
    Here are brief descriptions of some projects around the
    world that use <A HREF="home.html">Lua</A>.
    <BR>
    <UL>
    <LI><A HREF="#1">TeCGraf</A>
    <LI> ...
    </UL>
    
    <H3>
    <A NAME="1" HREF="http://www.tecgraf.puc-rio.br/">TeCGraf</A>
    <BR>
    <SMALL><EM>Computer Graphics Technology Group,
               PUC-Rio</EM></SMALL>
    </H3>
    
        TeCGraf is the result of a partnership between
        ...
        distributed among dozens of final products.<P>
    Contact: Waldemar Celes
    
    <A NAME="2"></A><HR>
    ...
    
    </BODY></HTML>

为了读取数据,程序所要做的就是为 entry 提供一个适当的定义,然后将数据文件作为程序运行(使用 dofile)。请注意,我们必须遍历所有条目两次,第一次是用于标题列表,第二次是用于项目描述。一种最初的方法是将所有条目收集到一个数组中。但是,由于 Lua 编译得非常快,因此还有一种有吸引力的解决方案:运行数据文件两次,每次都使用不同的 entry 定义。我们在下一个程序中遵循此方法。

首先,我们定义一个用于编写格式化文本的辅助函数(我们已经在 第 5.2 节 中看到了此函数)

    function fwrite (fmt, ...)
      return io.write(string.format(fmt, unpack(arg)))
    end

BEGIN 函数只是编写页面标题,该标题始终相同

    function BEGIN()
      io.write([[
        <HTML>
        <HEAD><TITLE>Projects using Lua</TITLE></HEAD>
        <BODY BGCOLOR="#FFFFFF">
        Here are brief descriptions of some projects around the
        world that use <A HREF="home.html">Lua</A>.
        <BR>
      ]])
    end

entry 的第一个定义将每个标题项目写为列表项。参数 o 将是描述项目的表

    function entry0 (o)
      N=N + 1
      local title = o.title or '(no title)'
      fwrite('<LI><A HREF="#%d">%s</A>\n', N, title)
    end
如果 o.titlenil(即未提供该字段),则该函数使用固定字符串 "(no title)"

第二个定义编写有关项目的全部有用数据。它稍微复杂一些,因为所有项目都是可选的。

    function entry1 (o)
      N=N + 1
      local title = o.title or o.org or 'org'
      fwrite('<HR>\n<H3>\n')
      local href = ''
    
      if o.url then
        href = string.format(' HREF="%s"', o.url)
      end
      fwrite('<A NAME="%d"%s>%s</A>\n', N, href, title)
    
      if o.title and o.org then
        fwrite('<BR>\n<SMALL><EM>%s</EM></SMALL>', o.org)
      end
      fwrite('\n</H3>\n')
    
      if o.description then
        fwrite('%s', string.gsub(o.description,
                                 '\n\n\n*', '<P>\n'))
        fwrite('<P>\n')
      end
    
      if o.email then
        fwrite('Contact: <A HREF="mailto:%s">%s</A>\n',
               o.email, o.contact or o.email)
      elseif o.contact then
        fwrite('Contact: %s\n', o.contact)
      end
    end
(为了避免与使用双引号的 HTML 发生冲突,我们在本程序中只使用单引号。)最后一个函数关闭页面
    function END()
      fwrite('</BODY></HTML>\n')
    end
最后,主程序启动页面,使用 entryentry0)的第一个定义运行数据文件以创建标题列表,然后使用 entry 的第二个定义再次运行数据文件,并关闭页面
    BEGIN()
    
    N = 0
    entry = entry0
    fwrite('<UL>\n')
    dofile('db.lua')
    fwrite('</UL>\n')
    
    N = 0
    entry = entry1
    dofile('db.lua')
    
    END()