Lua 概览
Lua 是一种在 MIT 许可证下发布的免费开源多范式编程语言。Lua 于 1993 年由 Roberto Lerusalimschy、Luiz Henrique de Figueiredo 和 Waldemar Celes 创建,是一种动态类型语言。它非常紧凑(编译后仅 150KB),主要用作脚本语言或另一种语言(主要是 C/C++)的扩展。
Lua 以库的形式实现,没有“main”程序。它仅在嵌入到宿主客户端时才工作。解释器是一个 C 程序,它使用 Lua 库来提供独立的 Lua 解释器。Lua 的目的不是为单一范式提供复杂而严格的规范,而是可以扩展以适应不同的问题类型。
由于体积小巧,Lua 可以安装在许多宿主平台上,并且已被移植并用于 PlayStation Portable 和 Nintendo DS 的视频游戏中,也用于更大的游戏中,例如 FarCry 和 World of Warcraft。《Adobe Photoshop Lightroom》摄影程序和 lighthttpd Web 服务器也已集成 Lua。Lua 具有一些高级特性,主要是类型强制转换、协程、垃圾回收、头等函数和动态模块加载。由于 Lua 体积小巧,因此仅包含少量数据类型。它试图在功能和体积小巧之间保持平衡。
在学习如何编写代码方面,Lua 与 Python 同样容易。在这两者中,Lua 通常是嵌入式系统的更好选择,仅仅是因为它更小。Lua 的优势在于处理字符串和表。它比 Python 更擅长处理逻辑方程式。
对于快速的 hack,Lua 程序员可以比 Python 程序员更快更轻松地处理复杂数据(尽管 Ruby 程序员也可以几乎同样快地做到这一点)。但是,对于处理大量复杂数据块的大型应用程序,Ruby 或 Python 等更重的语言可能是更好的选择。
无需担心不同类型的整数。您可能已经发现,不同类型的整数和数字(例如浮点数、长整型或双精度浮点数)可能会搞砸程序的输出,甚至在您粗心大意时导致程序崩溃。Lua 对每种整数和数字类型都使用强制转换,将其转换为单一类型。您可以将浮点数、长整型或双精度浮点数添加到任何其他类型的整数或数字中,而不会在 Lua 中出现问题。相比之下,这样做可能会导致用 Python 2.4 或更旧版本编写的程序崩溃。Lua 在语法上非常宽容。如果出于某种原因,您正在四英寸宽屏幕的嵌入式设备上编程怎么办?您可以减少行数和其他字符的数量,从而可以轻松阅读代码以弥补小屏幕的不足。
小即是美。程序员可以将 Lua 嵌入到其他几种语言中,例如 C/C++ 和 Java,而不会使宿主语言臃肿,因为 Lua 具有微小的 API。与 Lisp 的单一数据结构类似,表是 Lua 拥有的唯一数据结构机制。这使得表非常强大,因为通过少量工作,它们可以模拟更大型语言中的数据结构。
面向对象编程的实现是极简主义的。Lua 使用表和函数而不是类。
与 Python 相比,Lua 不专注于 100% 向后兼容。许多较新版本的 Lua 会破坏用以前版本编写的程序。幸运的是,Lua 开发人员总是会宣布新版本的 Lua 将会破坏什么。
Lua 支持线程。多个 Lua 解释器可以在同一进程中共存,并且每个解释器都可以在自己的线程中独立运行。这通常使 Lua 非常适合嵌入式系统中的多线程程序。
要从源代码编译和安装 Lua,请从 Lua.org 网站获取 Lua 5.1 的副本,然后解压、配置、生成并安装它
tar -xvzf lua-5.1.1.tar.gz cd lua-5.1.1 make xyz make xyz install
Lua 是一种动态类型语言,其语法与 Python 非常相似,甚至与 Ruby 更相似。换行符在 Lua 的语法中不起任何作用,就像 Python 或 Ruby 一样。例如,以下丑陋但有效的代码
foo = 89 bar = foo+2 print(bar)
由于体积小巧,Lua 只有八种基本数据类型
nil(类似于 Python 的 None)
布尔值
数字
字符串
函数
userdata(一种允许将任意 C 数据存储在 Lua 变量中的类型)
线程
表
Lua 仅支持少数几种数据结构,包括数组、列表和哈希表。
表类型实现了一个关联数组,可以使用任何值(类似于 Python)进行索引,但 nil 除外(与 Python 不同)。Nil 的目标是与任何其他值不同,以及作为全局变量的默认值。Nil 在 Lua 中也比 None 在 Python 中扮演更重要的角色。虽然表是 Lua 中唯一的数据结构机制(这可能看起来是一个缺点),但表与 Python 的字典和列表一样强大,甚至与 Ruby 的哈希一样强大。表用于表示许多不同类型的数组、集合、树和其他几种数据结构。表的一个方便的功能是使用字符串作为键——例如
x = { ["hello world!"] = "ciao world!" } print(x["hello world!"])
运行此示例时,Lua 输出的是 “ciao world!” 而不是 “hello world!”,正如它可能显示的那样。
要更深入地了解 Lua 的表,请访问 lua-users.org/wiki/TablesTutorial。
由于任何值都可以表示一个条件,因此 Lua 中的布尔值与其他许多语言中的布尔值不同。在 Lua 中,false 和 nil 都被认为是 false,但 Lua 将其他一切都视为 true(包括零和空字符串)。
与 Python 不同,全局变量不需要声明。要创建一个全局变量,请为其赋值。要删除它,请为其赋值 nil。全局变量只有在具有非 nil 值时才存在。与 Python 正好相反,Lua 中的大多数变量默认情况下都是全局变量,您必须将变量声明为“local”才能使其成为局部变量,而不是假设所有变量都是局部变量。
由于大多数 CPU 执行浮点运算的速度与整数运算的速度一样快,因此 Lua 中的数字表示实数、双精度浮点数,而不是普通整数。由于 Lua 不需要整数类型,因此它没有整数类型。这消除了舍入误差、浮点数和长整数。
Lua 非常擅长处理字符串,并且已用于处理几兆字节长的字符串。它在字符串和数字之间进行转换;应用于字符串的任何数值运算都会将字符串转换为数字。此转换原则仅适用于数字,因为当需要字符串时,Lua 会将数字转换为字符串。即使使用自动转换,Lua 仍然可以区分数字和字符串,例如 90 == “90”(始终为 false)。
不建议在 Lua 中使用以下划线开头的标识符(例如 _FOO),因为许多标识符保留用于特殊用途。只要标识符不以数字开头,该标识符就可以由下划线、字母和数字的组合组成。
您基本上可以重命名 Lua 中的任何内容,甚至可以将其重命名为不可调用的程度。例如,以下代码
x = io x.read() io = "Hello world!" x = "Let's make io uncallable!" io.read()
第二行通过 io 模块获取键盘输入。由于 io 本质上是一个以函数作为值的变量,您可以为其赋予不同的值,以便 io 不再与输入/输出函数相关。当您尝试再次从 io 模块获取键盘输入时,Lua 返回错误。现在程序无法调用输入/输出函数,因为 io 的值已被重新分配。为了再次使用 io,您必须重新启动 Lua 程序。
Lua 使用 .. 运算符连接字符串。请注意print("Hello".."World!")是有效的,但是print("I've said 'Hello World'"..5.."or more times.")是无效的。这是因为 Lua 将句点视为整数后的小数。运算符必须在字符串和整数之间留有空格。否则,它不会返回错误。以下代码有效地连接了字符串和整数
print("I've said 'Hello World' " ..5 .. " or more times.")
Lua 使用许多 Python、Ruby 和大多数其他语言使用的常用运算符。对于 Python/Ruby 逻辑非运算符,Lua 可以使用它,也可以使用 ~= 来表示不相等。始终记住,Lua 对待字符串和整数的方式不同"1" < 2始终为 false,并且字符串按字母顺序比较。
如果条件为 false,Lua 将结束 while 循环。Repeat-until 语句与 while 循环相反;它们循环直到条件为 true。for 循环有一些隐藏的曲折,这可能会让 Python 或 Ruby 程序员感到恼火。在 for 循环中创建的局部变量仅在循环内部可见。循环结束后变量不存在,因此如果您需要控制变量的值,则必须将其值保存到另一个循环中。出于语法原因,Break 或 return 只能作为循环中 end、else 或 until 之前的最后一个语句出现。
Lua 将函数视为“一等”值,并将它们用于 OOP(面向对象编程)。Lua 可以调用自己的函数或 C 函数,并且将函数作为一种类型来处理。您可以为变量赋予函数属性或使用 function() 方法创建它。如果您在 return 关键字后列出多个结果,则用 Lua 编写的函数可以返回多个结果。
Lua 支持 OOP,但由于 Lua 的大小,其 OOP 实现缺少一些功能。Lua 使用表和函数进行 OOP,而不是类。就像 Python 访问类中的函数或变量一样,Lua 使用 Table.function 或 Table.variable 访问它。
Lua 在多重赋值方面可能很挑剔,因为它会调整赋值值的数量。如果值的数量少于变量列表,则所有剩余的值都将赋予 nil 值。如果值的列表长于变量的数量,Lua 会默默地丢弃它们。
Lua 具有一些基本的 OOP 功能。self 参数是任何面向对象语言中不可或缺的概念,也是 Lua 拥有的少数 OOP 概念之一。许多面向对象语言倾向于向您隐藏 self 机制,以便您不必声明此参数。Lua 使用冒号运算符隐藏此参数。您还可以使用冒号、函数和表来模拟类。由于 Lua 没有类概念,因此每个对象都定义了自己的行为和形状
Earth = {martians = 5389} function Earth:casualties (survivors) Earth.martians = Earth.martians - survivors print("Earth is free! "..Earth.martians.." martians survived!") end Earth:casualties(5380)
上面示例中的冒号用于在方法定义中添加额外的参数。它还在方法调用中添加了额外的参数。您不必使用冒号。Lua 程序员可以使用点语法定义函数,并使用冒号语法调用它,或者反之亦然,如果他们添加额外的参数
Earth = {martians = 5389, casualties = function (self, survivors) self.martians = self.martians - survivors print("Earth is free! "..self.martians.." martians survived!") end } Earth.casualties(Earth, 5380) Earth.martians = 5389 Earth:casualties(5380)
在这种情况下,函数必须是表的一部分,以便可以通过点语法或冒号语法调用它。请注意,我还必须为函数提供 self 参数,才能使任一调用方法都有效。虽然这些是简单的 OOP 示例,仅涉及 OOP 的表面,但您可以在 Lua 参考手册或 Programming in Lua 一书中找到有关继承和其他 OOP 实现的信息(这两本书都可以从 Lua 网站免费获得)。
现在,让我们将 Lua 编程与 Python 编程进行比较。首先,让我们编写一个问答游戏。以下是一些简单的 Lua 代码,它使用表作为字典来存储问题和答案
print("What's your name?") name = io.read() questions = { ["Which came first? Minix or Unix?"] = "Unix", ["Who created Linux?"] = "Linus Torvalds", ["In what year was Linux created?"] = "1991" } correct_answers = 0 for key,value in pairs(questions) do print(key) answer = io.read() if answer == value then correct_answers = correct_answers + 1 end end if correct_answers == 0 then print("You need to browse Wikipedia!") else print("\nGood job, "..name.."!") print("Correct answers: "..correct_answers..") end
接下来,让我们逐行分解并分析它。在第二行,变量 name 被赋值为 io.read()。io 库有许多处理各种输入和输出的函数,但我仅将其用于键盘输入。
下一行是变量 questions。questions 变量的值是一个表,我已将其用作字典来存储问题和答案。问题在方括号中,以告知 Lua 它们是表的键。
跳过第三行,这里有一个 for 循环,其功能是使用 pairs() 查找表中每个项目的键和值。然后,它需要将键的值和键的值的值放入变量 key 和 value 中。
在打印键(其中包含问题)后,Lua 通过 io.read() 将用户的答案放入 answer 变量中,并检查它是否等于正确的答案。如果答案正确,则 correct_answers 变量的值加 1,并重复此过程,直到表中没有更多项目需要遍历。
接下来,Lua 检查用户是否回答正确了任何问题,然后打印一条消息,告诉用户了解更多关于 UNIX(及其变体)黑客历史的信息,或者祝贺用户回答正确的题数。请注意第 16 行上的连接运算符。
在 Python 中,执行上述游戏的最简单方法如下
name = raw_input("What's your name?\n") questions = {"Which came first? Minix or Unix?":"Unix", "Who created Linux?":"Linus Torvalds", "In what year was Linux created?":"1991"} correct_answers = 0 for key in questions: print key answer = raw_input() if answer == questions[key]: correct_answers += 1 if correct_answers == 0: print "You need to browse Wikipedia!" else: print "\nGood job, " + name + "!" print "Correct answers: ", correct_answers
您可能会注意到,在 Python 中获取键盘输入比在 Lua 中更容易,但字典在 Lua 中更容易识别并且看起来更漂亮。Python 中的 for 循环比 Lua 中的 for 循环稍微复杂一些,因为 Python 需要知道键才能获取键的值。在 Lua 中,pairs() 函数将键及其值从字典表中分离出来,这使得从表中获取数据比在 Python 中更简洁、更容易。至于代码行数,不计算众多的“ends”,Lua 以 13 行代码对 Python 的 17 行代码轻松获胜。即使 Lua 程序员需要输入更多内容,他们的代码也更容易筛选,尤其是在代码长达数千行时,因为 Lua 使用 end 而不是冒号(如 Python 中)。
现在,GUI 怎么样?用 Lua 编程 GUI 与用 Python 编程 GUI 相同、更简单还是更困难?在您尝试回答这个问题之前,请确定这两种语言中的哪个程序在没有注释的情况下更容易维护、阅读和理解。在这里,我使用 WxGTK 库作为 GUI。wxLua 的唯一问题是它是一个完全独立的程序。wxLua 应用程序无法使用常规 Lua 解释器运行,因此您必须使用wxlua程序。
这是一个使用 wxLua 制作的 GTK GUI 程序
frame = wx.wxFrame(wx.wxNull, wx.wxID_ANY, "wxLua App", wx.wxDefaultPosition, wx.wxSize(250, 50), wx.wxDEFAULT_FRAME_STYLE) frame:Show(true)
现在,这是用 GTK 完成相同工作但使用 wxPython 的程序的代码
from wxPython.wx import * class Main(wxApp): def OnInit(wxApp): frame = wxFrame(NULL, -1, "wxPython App") frame.Show(true) return true Main().MainLoop()
这一次,Lua 缺乏必要的格式和成熟的 OOP 使简单的工作变得更简单。wxLua 没有创建类和函数,而是将此 GUI 应用程序所需的一切都集成到一个系统函数中,而 Python 和 wxPython 则需要类和函数。另请注意,Lua 会自动导入系统库。此 wxLua 应用程序练习了我之前讨论的一些 Lua 的 OOP 功能。该应用程序创建框架,设置框架的名称和框架值,然后使用冒号从 wxFrame 方法中调用 Show() 函数。您也可以使用句点语法而不是冒号来调用框架
frame.Show(frame, true)
尽管查看 Lua 的嵌入和扩展超出了本文的范围,但我在此处介绍一些概念。首先,Lua API 非常简单明了。它的设计消除了嵌入 C 代码时手动引用的需要(与 Python 的 API 不同)。与语言一样,Lua 的 C API(用于嵌入)也相当简约。如果您需要高级功能,可以使用主要由预处理器宏组成的辅助库。
其次,C 和 C++ 并不是 Lua 可以嵌入的唯一语言。Tao.Lua 为 Lua 提供了直接的 .NET 和 Mono 绑定,LuaJava 允许用 Lua 编写的脚本操作 Java 组件。LuaJava 允许使用 Lua 用于访问其本机对象的相同语法从 Lua 访问 Java 组件。它还允许 Java 使用 Lua 接口,以便可以在 Lua 中实现任何接口并作为参数传递给任何方法。该方法的结果(在 Java 程序中调用时)在 Lua 中调用,结果将发送回 Java。
Lua 是一种灵活、强大、紧凑的语言,可以在各种情况下使用和扩展。它专注于简单性,使其易于调试,并吸引了许多用户。其简单、强大的语法因 Lua 的元机制而提供了灵活性。小型、快速的解释器比 Python 使用更少的资源,并且其语法使代码更易于阅读。其简单的 C API 使嵌入变得轻而易举。无论您是在进行数据处理、GUI 还是游戏编程,您都会发现 Lua 的用途。
资源
Lua 程序设计: www.lua.org/pil
lua-users: www.lua-users.org
wxPython: www.wxpython.org
xwPyWiki: wiki.wxpython.org
wxLua: wxlua.sourceforge.net
LuaJava: www.keplerproject.org/luajava
The Tao Framework: www.taoframework.com
Lua 与 Python 对比: www.lua-users.org/wiki/LuaVersusPython
Joseph Quigley 成为 Linux 用户已有两年多。他喜欢摆弄不同的 Linux 发行版和探索新的编程语言。