第04章 语句

赋值(assignment)

Lua 有个不同于 C, Java, JavaScript 等的赋值特点:它可以多重赋值——一次将多个值赋给多个变量。

a, b = "hello, world!", 2012
print(a, b) --> hello, world!    2012

多重赋值都是先对右边的元素求值,然后赋给左边的变量,如此,lua 中的值交换写起来比其他语言方便的多,一句话搞定:

a, b = b, a -- 交换 a 和 b
c[i], c[j] = c[j], c[i] -- 交换 c[i] 和 c[j]

局部变量和块(block)

局部变量以 local 声明,作用域仅限于它所在的块(block),或一个 chunck 。一个 block 是一个控制结构的执行体,或者是一个函数的执行体,或者是一个程序块(chunk)。一个函数的形参是这个函数体的局部变量。

如果局部变量和全局变量同名,可以如此处理:

local foo = foo -- 声明一个局部变量 foo, 并用全局变量 foo 来初始化它。

编程原则:“尽可能使用局部变量”。

控制结构

if/else

a = -33
if a > 0 then
    print(1)
elseif a == 0 then
    print(0)
else
    print("other")
end

if/else 结构如上例所示,其中 elseif 可有0个或多个,如果分支选择,最后一个分支必须用 else.

Lua 不支持 switch 结构,因此代码中可能出现大量的 if/else 语句。

while

local a = {"Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday"}
local i = 1
while a[i] do
    print(a[i])
    i = i + 1 -- lua 中貌似没有 ++ 和 -- 运算, 只能这么用
end

以上代码输出:

Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday

依次打印了数组的内容。

repeat

b = {-3, -2, -1, 0}
local i = 1
while b[i] > 0 do
    print(b[i])
    i = i + 1
end
i = 1
repeat
    local v = b[i]
    print(v)
until b[i] <0

上面的代码输出:

-3

是 repeat 循环的输出。repeat 有点像 do ... while 结构,至少执行一次。这里,循环体中的局部变量的作用域会延伸到条件测试部分

numberic for

Lua 中第一种 for 是所谓的 numberic for:

for var=start_value, end_value, step_value do
    <循环体>
end

for 关键字后以此是:起始值(start value),终止值(end value),步进量(step value)。其中 setp value 可选,如果不填写,系统缺省为1. for 的三个变量 start_value, end_value, step_value 是一次性求值的,并会被作为循环体内的局部变量。示例代码如下:

for p = 1, 100, 21 do
    print(p)
end

以上代码输出:

1
22
43
64
85

另一个例子:

a = {1, 2, 3; -3, -9}
local found = nil
for i=1, #a do
    if a[i] < 0 then
        found = i
        break
    end
end
print(found) --> 4
print(a[found]) --> -3

generic for

泛型 for (generic for), lua 中的第二种 for,它通过 iterator(迭代器) 函数来遍历所有的值。其实这东西,在 Java 中也有体现,如通过 for/each 遍历泛型数组或集合类等。

a = {1, 2, 3; -3, -9}
for i, v in ipairs(a) do
    print(v)
end

它的输出是:

1: 1
2: 2
3: 3
4: -3
5: -9

ipairs 函数由 lua 的基础库提供,用以遍历数组的迭代器函数。在每次循环中,i 被赋予当前遍历到的元素的索引值,v 就是被遍历到原书的值。这里 i 从1开始,所以要是把 a 中的元素改为从0开始的话,头一个元素就不显示的。

a = {[0]=1, 2, 3; -3, -9}
for i, v in ipairs(a) do
    print(tostring(i) .. ": " .. v)
end

的输出是:

1: 2
2: 3
3: -3
4: -9

上面的输出中,index 为0的元素没了。这里也可以看出把 index 设置为0带来的问题。

系统提供了几种迭代器:

  • io.lines 迭代文件中每行
  • pairs 迭代 table 元素
  • ipairs 迭代数组元素
  • string.gmatch 迭代字符串中单词

还可以自定义迭代器 TODO 这部分可以在将来单独整理(ch7 会单独讲到这个问题)

break/return

Lua 限定只能用于 block 或 chunk 的最后,如果中间要使用,可以显示用 do ... end 调用