Lua 教程

此教程基于 Programming in Lua, 4th edition。

因为在 Slurm 集群负载调度器 部署中,会用到用 Lua 实现的 Lmod 这个环境模块系统,故有必要了解 Lua 这门编程语言。

前言

早在 1993 年,当 Waldemar、Luiz 和我(作者)开始开发 Lua 时,我们很难想象,他会像现在这样传播开来。起初,Lua 只是为两个特定项目,开发的内部语言,而现在,他已被广泛应用于嵌入式系统、移动设备、物联网、游戏等,所有能够从简单、可扩展、可移植和高效的脚本语言受益的领域。

Lua 从一开始,就是为与 C 语言,及其他传统语言编写的软件集成,而设计的。这种语言双重性,带来了许多好处。Lua 是一种微小,且简单的语言,部分原因是他并不试图,做 C 语言已经擅长的事情,譬如纯粹的性能、底层操作,或与第三方软件的接口。Lua 依靠 C 语言,完成这些任务。Lua 所提供的,是 C 语言所不擅长的:与硬件保持良好距离、动态的结构、无冗余、易于测试和调试。为此,Lua 拥有安全的环境、自动内存管理,以及处理字符串及其他动态数据的强大功能。

除了是一门可扩展的语言,Lua 还是一门 胶水语言,glue language。Lua 支持基于组件的软件开发方法,a component-based approach to software development,我们通过将现有的高级组件粘合在一起,来创建出应用程序。通常,这些组件是用 C 或 C++ 等静态类型语言,编写编译的;Lua 是我们用来组成,和连接这些组件的胶水。通常,组件(或对象)代表了更具体、更低级的概念(如视窗小部件及数据结构),这些具体、低级概念,在程序开发过程中不会有太多变化,并占用了最终程序的大部分 CPU 时间。Lua 提供了应用程序的最终形态,在产品的生命周期内,他们则可能会发生很大变化。不过,与其他胶水技术不同,Lua 本身也是一种成熟的语言。因此,我们不仅可以使用 Lua 来粘合组件,还可以调整和重塑组件,甚至创建出全新组件。

当然,Lua 并不是唯一的脚本语言,scripting language。咱们还可以使用其他语言,来实现大致相同的目的,例如 Perl、Tcl、Ruby、Forth 与 Python 等。Lua 有别于这些语言的特点如下;虽然其他语言与 Lua 共享了其中一些特点,但并没有其他语言,提供了类似的功能:

  • 可扩展能力,extensibility:Lua 的可扩展性非常出色,以至许多人认为,Lua 不是一门语言,而是一种用于构建特定领域语言,domain-specific languages,的工具包。Lua 从一开始,就被设计成可以通过 Lua 代码,和外部 C 代码进行扩展。作为概念验证,他通过外部库,实现了自身的大部分基本功能。将 Lua 与 C/C++,以及其他语言(如 Fortran、Java、Smalltalk、Ada,甚至其他脚本语言)连接起来,非常容易;

  • 简洁,simplicity:Lua 是一门简单而小巧的语言。他的概念很少(但功能强大)。这种简洁性使 Lua 易于学习,并有助于小型实施。他的完整发行版(源代码、手册以及某些平台的二进制文件)可轻松放入软盘中;

  • 高效率,efficiency:Lua 的实现相当高效。独立的基准测试表明,Lua 是脚本(解释型)语言领域,速度最快的语言之一;

  • 可移植性,portability:在谈论可移植性时,我们并不是在谈论,同时在 Windows 和 Unix 平台上运行 Lua。我们指的是在我们听说过的所有平台上运行 Lua: NextStep、OS/2、PlayStation II(索尼)、Mac OS-9 和 OS X、BeOS、MS-DOS、IBM 大型机、EPOC、PalmOS、MCF5206eLITE 评估板、RISC OS,当然还有各种 Unix 和 Windows。这些平台的源代码几乎相同。Lua 不使用条件编译,来使代码适应不同的机器;相反,他坚持使用标准 ANSI (ISO) C: 如果咱们有 ANSI C 编译器,只需编译 Lua 即可。

Lua 的大部分能力,都来自他的库。这并非偶然。Lua 的主要优势之一,便是其通过一些新类型及新函数,实现的可扩展性。许多特性,都有助于增强这一优势。动态类型,允许很大程度的多态,polymorphism。自动的内存管理简化了接口,因为无需决定由谁,负责分配和取消分配内存,也无需决定,如何处理内存溢出。高阶函数与匿名函数,允许高度参数化,使函数用途更加广泛。

Lua 附带了一套小型的标准库。在诸如嵌入式处理器等限制较多的环境中,安装 Lua 时,谨慎选择所需的库,可能是明智之举。此外,如果限制条件苛刻,则可以很容易地进入库的源代码,逐一选择需要保留的功能。不过,请记住,Lua 的体积很小(即使包含所有标准库),在大多数系统中,咱们都可以毫无顾虑地,使用整个软件包。

受众群体

Lua 用户通常分为三大类:在应用程序中嵌入 Lua 的用户、单独使用 Lua 的用户,以及同时使用 Lua 和 C 语言的用户。

许多人将 Lua 嵌入到应用程序中,如 CGILua(用于构建动态网页)或 LuaOrb(用于访问 CORBA 对象)。这些应用程序,使用 Lua-C API,来注册新函数、创建新类型,并更改某些语言操作的行为,从而为其特定领域配置 Lua。通常,这些应用程序的用户,甚至不知道 Lua 是一门独立、适用于特定领域的语言;例如,CGILua 用户往往认为,Lua 是一种专门为网络设计的语言。

Lua 作为一门独立的语言,也很有用,主要用于文本处理和一次性小程序,one-shot programs。对于此类用途,Lua 的主要功能来自其标准库,这些库提供了模式匹配,及其他字符串处理的功能。我们可以将这种独立语言,视为 Lua 在字符串和(文本)文件处理领域的嵌入。

最后,还有一些程序员在工作台的另一侧工作,编写将 Lua 作为库,使用的应用程序。尽管他们需要对 Lua 有很好的理解,才能创建出简单、易用,且与 Lua 语言完美结合的用户界面,但他们更多的是使用 C 语言,而非 Lua 进行编程。

本书结构

除了与 Lua 5.3 版本相关的新材料:整数、位运算、无符号整数等之外,本书这一版本(第 4 版)还增加了许多领域的新材料和示例,包括沙盒操作,sandboxing、例程 coroutines、日期和时间操作等。

更重要的是,这一版对教材进行了重大调整。我不再围绕语言组织材料(例如,每个库都有单独的章节),而是尝试围绕编程中的共同主题,组织材料。这种编排方式,使本书能够更好地按照复杂性递增的顺序,进行编排,而将简单的主题放在首位。这种顺序来自于教授该语言课程的经验;特别是,我认为这种新的编排方式,更适合将本书作为涉及 Lua 的课程的教学资源。

与前一版本一样,本版分为四个部分,每部分约九章。不过,各部分都有一个相当新的特点。

第一部分涵盖语言的基础知识(命名为 基础知识,The Basics 再合适不过了)。他围绕 Lua 中的主要值类型展开:数字、字符串、表格和函数。他还涵盖了基本的 I/O,并概述了该语言的语法。

第二部分名为 实战编程,Real Programming,涵盖了在其他类似语言中,也能找到的高级主题,例如闭包、模式匹配、日期和时间操作、数据结构、模块和错误处理。

第三部分名为 Lua 主义,Lua-isms。顾名思义,他涵盖了 Lua 与其他语言相比,特别不同的方面,例如元表,metatables,及其用途、环境、弱表,weak tables、例程,coroutines和反射, reflection。这些也是 Lua 语言中较为高级的内容。

最后,与前几版一样,本书最后一部分,介绍了 Lua 和 C 之间的 API,供使用 C 来充分发挥 Lua 功能的读者参考。这部分内容的风格,必然与本书其他部分截然不同。在那里,我们将使用 C 语言,而不是 Lua 语言进行编程;因此,我们将戴上一顶不同的帽子。对于某些读者来说,对 C API 的讨论可能兴趣不大;而对于另一些读者来说,这可能是本书最相关的部分。

在所有部分中,我们重点关注不同的语言结构,并通过大量示例和练习,来展示如何在实际任务中使用他们。我们还在各章之间,安排了一些插曲,interlude。每个插曲都介绍了一个简短,但完整的 Lua 程序,让读者对该语言有更全面的了解。

其他资源

对于想要真正学习任何语言的人来说,参考手册都是必备的。本书并不能取代 Lua 参考手册。恰恰相反,两者相辅相成。手册只描述了 Lua。他既没有举例说明,也没有说明语言结构的原理。另一方面,他描述了整个语言;而本书则跳过了语言中,一些很少使用的阴暗角落。此外,手册是关于 Lua 的权威文档。如果本书与手册存在分歧,请相信手册。要获取手册和更多关于 Lua 的信息,请访问 Lua 网站 lua.org

咱们还可以在 Lua 用户网站上,找到有用的信息,该网站由 lua-users.org 用户社区维护。除其他资源外,该网站还提供了教程、第三方软件包和文档列表,以及官方 Lua 邮件列表存档。

本书讲的是 Lua 5.3,不过其中的大部分内容,也适用于以前的版本,甚至可能也适用于未来的版本。Lua 5.3 与旧版本 Lua 5 之间的所有差异,都在文中明确标出。如果咱们使用的是较新版本(在本书之后发布),请查阅相应手册,了解不同版本之间的差异。

一些排版约定

本书将 "字面字符串" 括在双引号之间,将单字符(如 a)括在单引号之间。用作模式的字符串,也用单引号括起来,如 '[%w_]*'。本书对代码块和标识符,都使用打字机字体。对于保留字,则使用黑体字。较大的代码块以下面的样式显示:

-- program "Hello World"
print("Hello World") --> Hello World

注解 --> 表示语句的输出,或表达式的结果:

print(10) --> 10
13 + 3 --> 16

在 Lua 中,双连字符 (--) 会开启一条注释,因此在代码中加入这些注释,不会有任何问题。

书中有一些代码片段,主要是在最初几章,应在交互模式下输入。在这种情况下,我(作者)在每一行,都使用了显示 Lua 提示符( >)的注解:

> 3 + 5             --> 8
> math.sin(2.3)     --> 0.74570521217672

在 Lua 5.2 及更早的版本中,在交互模式下,要打印表达式的结果,就必须在表达式前加上等号:

> = 3 + 5       --> 8
> a = 25
> = a           --> 25

出于兼容性考虑,Lua 5.3 仍然接受这个等号。

最后,本书使用注解 <-->,来表示某事物与另一事物等价:

this <--> that

运行示例

咱们需要 Lua 解释器,来运行本书中的那些示例。理想情况下,咱们应该使用 Lua 5.3,但大多数示例无需修改,即可在旧版本上运行。

Lua 网站(lua.org 保存了解释器的源代码。如果咱们有一个 C 语言编译器,并且知道如何在自己机器上编译 C 代码,那么就应该尝试从源代码安装 Lua;这真的很容易。Lua 二进制网站(搜索 luabinaries)为大多数主流平台,提供了预编译 Lua 解释器。如果咱们使用的是 Linux,或其他类 UNIX 系统,则可以查看发行版的软件仓库;一些发行版已经提供了包含 Lua 的软件包。

有多种 Lua 集成开发环境 (IDE)。同样,咱们也可以通过基本搜索,轻松找到它们。(不过,我(作者)是个老手。我还是更喜欢在一个窗口中,使用命令行界面,在另一个窗口中使用文本编辑器,尤其是在初始学习阶段)。

致谢

本书第一版出版至今(2017 年 4 月),已有十余年。这一路走来,有几位朋友和一些机构给予了我(作者)帮助。

一如既往,Lua 的合作作者 Luiz Henrique de Figueiredo 和 Waldemar Celes,提供了各种帮助。André Carregal、Asko Kauppi、Brett Kapilik、Diego Nehab、Edwin Moragas、Fernando Jefferson、Gavin Wraith、John D. Ramsdell、Norman Ramsey、Reuben Thomas 和 Robert Day 为本书的不同版本,提供了宝贵建议和有益见解。Luiza Novaes 为封面设计提供了重要支持。

Lightning Source Inc.,是印刷和发行本书的可靠而高效的选择。如果没有他们,就不可能选择自行出版这本书。

由 Marcelo Gattass 领导的 Tecgraf 公司,从 1993 年 Lua 项目诞生到 2005 年,一直为其提供支持,并继续在多个方面为该项目提供帮助。

我还要感谢 里约热内卢天主教大学,PUC-Rio,和 巴西国家研究委员会,the Barzilian National Research Council, CNPq,对我工作的持续支持。特别是,如果没有里约热内卢天主教大学为我提供的环境,Lua 项目是不可能完成的。

最后,我必须向 Noemi Rodriguez 表示深深的谢意,感谢她提供的各种帮助(技术性和非技术性的),感谢她照亮了我的人生。

Last change: 2024-02-02, commit: aaba197