按照老规矩, 我们编写的第一个 Lua 程序要做的就是打印出 "Hello World"
:
print("Hello World")
单机(stand-alone)的 Lua 解释器通常被命名为 lua
或者 lua5.2
, 在安装了这一解释器的电脑上, 我们只需要调用解释器并给出包含程序源码的文件名就可以执行指定的程序了。 比如说, 如果程序的文件名为 hello.lua
, 那么只要执行以下命令就可以运行它:
% lua hello.lua
下面展示的这个程序稍微更复杂一些, 它定义了一个用于为给定数字计算阶乘的函数, 这个函数会要求用户输入一个数字, 并打印出这个数字的阶乘:
-- 定义一个阶乘函数 function fact (n) if n == 0 then return 1 else return n * fact(n-1) end end print("enter a number:") a = io.read("*n") -- 读入一个数字 print(fact(a))
Lua 执行的每一段代码, 比如一个文件或者交互模式下的一个输入行, 都被称为 代码块 。 一个代码块就是一连串的命令或者声明。
Lua 代码并不需要在多个连续的声明之间使用分隔符, 但如果你觉得有需要的话, 也可以使用分号来对声明进行分割。 作者本人的习惯是只使用分号来分割同一行上面的多个声明。 断行在 Lua 语法中并无实际意义; 比如说, 以下四个代码块在语法上都是合法并且等价的:
a = 1 b = a*2 a = 1; b = a*2; a = 1; b = a*2 a = 1 b = a*2 -- 这样写虽然不好看,但也是合法的
代码块既可以像之前提到的 "Hello World"
例子一样, 只包含一个简单的声明, 又可以像之前提到的阶乘函数例子一样, 由多个声明以及函数定义组成 (稍后我们就会看到,定义函数实际上就是为变量赋值)。 因为 Lua 在用作数据描述语言(data-description langauge)的时候常常需要处理好几个 MB 大小的代码块, 所以 Lua 解释器在处理大代码块方面没有任何问题, 用户完全可以按照自己的需要决定代码块的大小。
除了将程序写在文件里面, 我们还可以通过解释器的交互模式来执行代码。 只要在不给定任何参数的情况下调用 lua
, 解释器就会打印出它以下提示符:
% lua Lua 5.2 Copyright (C) 1994-2012 Lua.org, PUC-Rio >
在此之后, 你键入的每条命令(比如 print "Hello World"
)都会立即被执行。 要退出交互模式以及解释器, 你可以键入文件结束控制符(在 UNIX 上面为 ctrl-D
,在 Windows 上面为 ctrl-Z
), 或者键入 os.exit()
, 通过调用操作系统函数库中的 exit()
函数来进行退出。
当 Lua 以交互模式运行时, 它通常会将键入的每行代码解释为一个完整的代码块, 如果输入的内容并不足以构成一个完整的代码块, 那么它就等待更多键入内容, 直到已键入的内容能够构成一个完整的代码块为止。 这使得用户可以通过交互模式键入包含多个行的定义, 比如说直接在交互模式里面定义 factorial
函数。 不过一般来说, 我们更习惯将复杂的定义写入到文件里面, 然后再调用 Lua 去运行那个文件。
通过给定 -i
选项, 我们可以让 Lua 在运行给定的代码块之后, 启动一个交互会话:
% lua -i prog
这个命令首先会运行 prog
文件包含的代码块, 然后进入交互模式。 这在进行调试或者手动进行测试的时候非常有用。 本章的最后会介绍更多可用的解释器选项。
另一种运行代码块的方式是使用 dofile
函数, 这个函数可以立即执行给定的文件。 举个例子, 对于包含以下代码的 lib1.lua
文件:
function norm (x, y) return (x^2 + y^2)^0.5 end function twice (x) return 2*x end
我们只需要在交互模式里面键入以下内容, 就可以执行它:
> dofile("lib1.lua") -- 载入库文件 > n = norm(3.4, 1.0) > print(twice(n)) --> 7.0880180586677
dofile
函数对于测试代码段也非常有用。 你可以同时打开两个窗口: 一个窗口运行编辑器, 对你的程序进行编辑(比如说 prog.lua
); 而另一个窗口则是一个控制台(console), 上面以交互模式运行着 Lua 。 这样在每次修改程序之后, 就可以通过在控制台输入 dofile("prog.lua")
载入新代码, 并对新代码进行测试。
Lua 的标识符(或者名字)可以是任何由字母、数字、下划线组成,但不以数字开头的字符串; 比如:
i j i10 _ij aSomewhatLongName _INPUT
用户应该避免定义以下划线为开头, 后面跟着一个或多个大写字母的标识符(比如 _VERSION
), 因为 Lua 会保留这种类型的标识符用于特殊用途。 不过我们通常会将单个下划线 _
用作临时变量。
旧版的 Lua 会根据系统的本地化设置对字母进行调整, 然而这种做法却使得不支持相同本地化设置的系统无法运行已经编写好的程序, 因此 Lua 5.2 只允许使用 A-Z
和 a-z
范围内的字母作为标识符。
以下是 Lua 语言的保留字, 它们不能被用作标识符:
and break do else elseif end false goto for function if in local nil not or repeat return then true until while
Lua 能够正确区分字母的大小写(case-sensitive)。 举个例子, 尽管 and
是一个保留字, 但 And
和 AND
却是两个不同的标识符。
Lua 的注释可以在任何地方以两个连字符为开始( --
), 注释的作用会持续到一行的末尾。 Lua 也提供以 --[[
为开始, 以 ]]
为结束的块注释。 块注释的一大妙用就是包围起暂时不想运行的代码段, 就像这样:
--[[ print(10) -- no action (commented out) --]]
要重新运行被包围的代码, 只需要在块注释的开头再加一个连字符就可以了:
---[[ print(10) --> 10 --]]
在第一个例子里面, --[[
在第一行开始了一个块注释, 而最后一行的两个连字符仍然处于块注释的作用范围之内。 但是在第二个例子里面, 字符串序列 ---[[
产生的却是一个普通的行注释, 因此代码的第一行和最后一行都会成为独立的注释, 而处于中间的 print
调用并不在注释的作用范围之内, 因此它可以如常地被执行。
Lua 的全局变量不需要进行预定义(declaration), 可以直接使用。 访问一个未初始化的变量并不会产生错误, 而是会得到一个空值:
print(b) --> nil b = 10 print(b) --> 10
如果把空值赋给某个全局变量, 那么这个全局变量在 Lua 里面就会表现得好像从来没有被使用过一样:
b = nil print(b) --> nil
在执行这一赋值操作之后, Lua 将会找个时间把这个全局变量曾经使用过的内存释放掉。