2.4 lua 控制结构
流程控制语句对于程序设计来说特别重要,它可以用于设定程序的逻辑结构。一般需要与条件判断语句结合使用。Lua 语言提供的控制结构有 if,while,repeat,for,并提供 break 关
键字来满足更丰富的需求。
if/else
if-else 是我们熟知的一种控制结构。Lua 跟其他语言一样,提供了 if-else 的控制结构。语法上更接近shell的语言,逻辑结构上和其他语言没有较大的区别,直接上实例,一看便知。
单分支if-end
1 | x = 10 |
双分支if-else-end
1 | x = 10 |
多分支if-elseif-else-end
1 | score = 90 |
**特别注意|**与 C 语言的不同之处是 else 与 if 是连在一起的,若将 else 与 if 写成 “else if” 则相当于在else 里嵌套另一个 if 语句,如下代码:
1 | score = 0 |
从上述实例中可以发现,除了else if
这种形式较elseif
多了一个end
外看起来并没有什么区别。上述实例中else if
在判断的最后,如果在中间的话,意味着后面的elseif
将会出现语法错误。
while
Lua 跟其他常见语言一样,提供了 while
控制结构,语法上也没有什么特别的。但是没有提供do-while 型的控制结构,但是提供了功能相当的 repeat
。while
型控制结构语法如下,当表达式值为假( 即 false
或 nil
) 时结束循环。也可以使用break 语言提前跳出循环。
1 | while 表达式 do |
1 | --示例代码,求 1 + 2 + 3 + 4 + 5 的结果 |
特别注意:
Lua 并没有像许多其他语言那样提供类似 continue
这样的控制语句用来立即进入下一个循环迭代( 如果有的话) 。因此,我们需要仔细地安排循环体里的分支,以避免这样的需求。
没有提供 continue
,却也提供了另外一个标准控制语句 break
,可以跳出当前循环。例如遍历 table
,查找值为 11
的数组下标索引:
1 | local t = {1, 3, 5, 8, 11, 18, 21} |
repeat
Lua 中的 repeat
控制结构类似于其他语言( 如:C++ 语言) 中的 do-while,但是控制方式是刚好相反的。简单点说,执行 repeat
循环体后,直到 until
的条件为真时才结束,而其他语言( 如:C++ 语言) 的 do-while 则是当条件为假时就结束循环。
1 | x = 10 |
除了条件相反外,repeat
和while
是一样的。
for
for 语句有两种形式:数字 for( numeric for) 和范型 for( generic for)。
数字for
1 | for var = begin, finish, step do |
关于数字 for 需要关注以下几点:
- var 从 begin 变化到 finish,每次变化都以 step 作为步长递增 var;
- begin、finish、step 三个表达式只会在循环开始时执行一次;
- 第三个表达式 step是可选的,默认为 1;
- 控制变量 var 的作用域仅在 for 循环内,需要在外面控制,则需将值赋给一个新的变量;
- 循环过程中不要改变控制变量的值,那样会带来不可预知的影响.
1 | for i = 10, 1, -1 do |
如果不想给循环设置上限的话,可以使用常量 math.huge:
1 | for i = 1, math.huge do |
泛型for
泛型 for 循环通过一个迭代器( iterator) 函数来遍历所有值:
1 | -- 打印数组a的所有值 |
结果:
1 | index: 1 value: a |
注意到在上述实例中使用到ipairs
函数。Lua 的基础库提供了ipairs
,这是一个用于遍历数组的迭代器函数。在每次循环中,i 会被赋予一个索引值,同时 v 被赋予一个对应于该索引的数组元素值。那么如何遍历table
呢?lua提供了pairs
函数可以遍历tbale
中的key
.
1 | -- 打印table t中所有的key |
从外观上看泛型 for 比较简单,但其实它是非常强大的。通过不同的迭代器,几乎可以遍历所有的东西, 而且写出的代码极具可读性。标准库提供了几种迭代器,包括用于迭代文件中每行的( io.lines) 、 迭代 table 元素的( pairs) 、迭代数组元素的( ipairs) 、迭代字符串中单词的( string.gmatch) 等。
泛型 for 循环与数字型 for 循环有两个相同点:
- 循环变量是循环体的局部变量;
- 决不应该对循环变量作任何赋值。
特别注意:在 LuaJIT 2.1 中, ipairs() 内建函数是可以被 JIT 编译的,而 pairs() 则只能被解释执行。因此在性能敏感的场景,应当合理安排数据结构,避免对哈希表进行遍历。事实上,即使未来 pairs 可以被 JIT 编译,哈希表的遍历本身也不会有数组遍历那么高效,毕竟哈希表就不是为遍历而设计的数据结构。