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


25 – 扩展您的应用程序

Lua 的一个重要用途是作为配置语言。在本章中,我们将说明如何使用 Lua 来配置程序,从一个简单的示例开始,然后逐步扩展它来执行更复杂的任务。

作为我们的第一个任务,让我们设想一个简单的配置场景:您的 C 程序(我们称之为pp)有一个窗口,您希望用户能够指定初始窗口大小。显然,对于如此简单的任务,有几个选项比使用 Lua 更简单,例如环境变量或带有名称-值对的文件。但即使使用一个简单的文本文件,您也必须以某种方式解析它;因此,您决定使用 Lua 配置文件(即碰巧是 Lua 程序的纯文本文件)。在其最简单的形式中,此文件可以包含类似于以下几行的内容

    -- configuration file for program `pp'
    -- define window size
    width = 200
    height = 300

现在,您必须使用 Lua API 指示 Lua 解析此文件,然后获取全局变量widthheight的值。以下函数可以完成此工作

    #include <lua.h>
    #include <lauxlib.h>
    #include <lualib.h>
    
    void load (char *filename, int *width, int *height) {
      lua_State *L = lua_open();
      luaopen_base(L);
      luaopen_io(L);
      luaopen_string(L);
      luaopen_math(L);
    
      if (luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
        error(L, "cannot run configuration file: %s",
                 lua_tostring(L, -1));
    
      lua_getglobal(L, "width");
      lua_getglobal(L, "height");
      if (!lua_isnumber(L, -2))
        error(L, "`width' should be a number\n");
      if (!lua_isnumber(L, -1))
        error(L, "`height' should be a number\n");
      *width = (int)lua_tonumber(L, -2);
      *height = (int)lua_tonumber(L, -1);
    
      lua_close(L);
    }
首先,它打开 Lua 包并加载标准库(它们是可选的,但通常最好备用)。然后,它使用luaL_loadfile从文件filename加载块,并调用lua_pcall来运行它。如果在任何这些函数中出现错误(例如,配置文件中的语法错误),则调用将返回一个非零错误代码并将错误消息推送到堆栈。与往常一样,我们的程序使用带有索引-1lua_tostring从堆栈顶部获取消息。(我们在第 24.1 节中定义了error函数。)

在运行块之后,程序需要获取全局变量的值。为此,它调用两次lua_getglobal,其唯一参数(除了无所不在的lua_State)是变量名。每个调用将相应的全局值推送到堆栈顶部,以便宽度位于索引-2,高度位于索引-1(顶部)。(因为堆栈之前是空的,所以您还可以从底部索引,从第一个值使用1,从第二个值使用2。但是,通过从顶部索引,即使堆栈不为空,您的代码也能正常工作。)接下来,我们的示例使用lua_isnumber来检查每个值是否为数字。然后,它使用lua_tonumber将此类值转换为double,而 C 将其强制转换为int。最后,它关闭 Lua 状态并返回。

是否值得使用 Lua?正如我之前所说的,对于如此简单的任务,一个只包含两个数字的简单文件比 Lua 要容易使用得多。即便如此,使用 Lua 也带来了一些优势。首先,Lua 为你处理所有语法细节(和错误);你的配置文件甚至可以有注释!其次,用户已经能够使用它进行更复杂的配置。例如,脚本可以提示用户提供一些信息,或者可以查询环境变量以选择合适的大小

    -- configuration file for program `pp'
    if getenv("DISPLAY") == ":0.0" then
      width = 300; height = 300
    else
      width = 200; height = 200
    end
即使在如此简单的配置场景中,也很难预料用户想要什么;但只要脚本定义了这两个变量,你的 C 应用程序就可以在不进行更改的情况下工作。

使用 Lua 的最后原因是现在可以轻松地为你的程序添加新的配置功能;这种轻松性创造了一种态度,从而产生更灵活的程序。