Lua的控制结构

Lua语言提供了一组精简且常用的控制结构,包括用于条件执行的if以及用户循环的while、repeat和for。所有的控制结构语法上都有一个显示的终结符:end用于终结if、for及while结构,until用于终结repeat结构。

控制结构的条件表达式的结果可以是任何值。Lua语言将所有不是false和nil的值当做真。

if then else

if 语句先测试其条件,并根据条件是否满足执行相应的then部分或else部分。else部分是可选的。

1
2
3
4
5
6
7
8
if a<0 then a == end

if a <b then return a else return b end

if line > MAXLINES then
showpage()
line = 0
end

如果要编写嵌套的if语句,可以使用elseif。它类似于在else后面紧跟一个if,但可以避免重复使用end:

1
2
3
4
5
6
7
8
9
10
11
if op == "+" then
r = a + b
elseif op == "-" then
r = a - b
elseif op == "*" then
r = a * b
elseif op == "/" then
r = a / b
else
error("invalid operation")
end

由于Lua语言不支持switch语句,所以这种一连串的else-if语句比较常见。

while

当条件为真时while循环会重复执行其循环体。Lua语言先测试while语句的条件,若条件为假则循环结束;否则,Lua会执行循环体并不断地重复这个过程。

1
2
3
4
5
local i = 1
while a[i] do
print(a[i])
i = i + 1
end

repeat

repeat-until语句会重复执行其循环体知道条件为真时结束。由于条件测试在循环体之后执行,所以循环体至少会执行一次。

1
2
3
4
5
6
-- 输出第一个非空的行
local line
repeat
line = io.read()
until line ~= " "
print(line)

和大多数其他编程语言不同,在Lua语言中,循环体内声明的局部变量的作用于包括测试条件:
1
2
3
4
5
6
-- 使用Newton-Raphson法计算"x"的平方根
local sqr = x / 2
repeat
sqr = (sqr + x / sqr) /2
local error = math.abs(sqr^2 - x)
until error < x/ 10000 -- 局部变量'error'此时仍然可见

数值型for

for 语句有两种形式:数值型for和泛型for。
数值型for的语法如下:

1
2
3
for var = exp1 , exp2, exp3 do
something
end

在这种循环中,var的值从exp1变化到exp2之前的每次循环会执行something。并且在每次循环结束后将步长exp3增加到var上。第三个表达式exp3是可选的,若不存在,Lua语言会默认步长值为1.如果不想给循环设置上限,可以使用常量math.huge:
1
2
3
4
5
6
for i = 1, math.huge do 
if (0.3*i^3 - 20*i^2 - 500 >= 0 ) then
pirnt(i)
break
end
end

为了更好地使用for循环,还需要了解一些细节。首先,在循环开始前,三个表达式都会运行一次;其次,控制变量是被for语句自动声明的局部变量,且其作用范围仅限于循环体内。一种典型的错误是认为控制变量在循环结束后仍然存在:
1
2
for i = 1 , 10 do print(i) end
max = i -- 可能会出错

如果需要在循环结束后使用控制变量的值,则必须将控制变量的值保存到另一个变量中:
1
2
3
4
5
6
7
8
9
10
-- 在一个列表中寻找一个值
local found = nil
for i = 1 , #a do
if a[i] < 0 then
found = i
break
end
end

print(found)

最后,不要改变控制变量的值,随意改变控制变量的值可能产生不可预知的结果。如果要在循环正常结束前停止for,那么可以使用break语句。

泛型for

泛型for遍历迭代函数返回的所有值。例如我们已经在很多示例中看到过的pairs、ipairs和io.lines等。虽然泛型for看似简单,但它的功能非常强大。使用恰当的迭代器可以在保证代码可读性的情况下遍历几乎所有的数据结构。
当然,我们也可以自己编写迭代器。尽管泛型for的使用很简单,但编写迭代函数却有不少细节需要注意。
与数值型for不同,泛型for可以使用多个变量,这些变量在每次循环时都会更新。当第一个变量变为nil时,循环终止。像数值型for一样,控制变量时循环体中的局部变量,我们也不应该在循环中改变其值。