本文主要记录一下Lua语言中的代码块和控制结构。

在交互模式中,每一行代码就是一个代码段。

do...end用来显式定义代码块。控制结构(if then else endwhile endrepeat untilfor end)也是一个代码块。

代码块

代码块通常是一个控制结构的主体,或者一个函数的主体,或者一个代码段(变量被声明时所在的文件或者字符串)。

在交互模式中,每一行代码就是一个代码段

do...end可以用来显式定义一个代码段。

局部变量

Lua中的变量默认是全局的,局部变量在使用前必须声明。

与全局变量不同,局部变量的作用域仅限于其代码块。

在交互模式中,每一行代码就是一个代码段,因此形如:

x = 10
local i = 1
while i <= x do
    local x = i * 2
    print(x)
    i = i + 1
end

在交互模式中运行时,变量iwhile语句中相当于重新被声明为全局变量,并且被赋值为nil,此时进行比较就会出错(stdin:1: attempt to compare nil with number)。

控制结构

Lua语言提供了一组精简且常用的控制结构,包括用于条件执行的if以及用于循环的whilerepeatfor

所有的控制结构都有一个显示的终结符:end用于中介iffor以及while结构,until用于终结repeat

控制结构的条件表达式可以是任何值。Lua语言将所有不为falsenil的值都当作真,空字符串和0也会被当作真值。

if then else end

if条件为真执行then否则执行elseelseif(前提是存在elseelseif)。

Lua语言不支持switch语句,因此一连串的if elseif很常见。

while

while条件为真执行循环体,条件为假则退出循环。

repeat

类似于do...whilerepeat...until语句也会执行循环体直到条件为真时结束。

由于条件测试在循环体之后执行,所以循环体至少会执行一次。

Lua语言中,循环体内声明的局部变量的作用域包括测试条件

local start = 3
repeat
    local x = start
    print(x)
until x == 3
-- $ lua repeat_until.lua
-- 3

数值型for

for语句有两种形式:数值型和泛型。

数值型for的语法如下:

for var = exp1, exp2, exp3 do
    ...
end

在这种循环中,var变量从exp1增长到exp2的过程中每次循环都会执行循环体,其中exp3为步长。

exp3是可选的,若不存在,Lua语言会默认步长值为1。

如果不想给循环设置上限,可以使用常量math.huge

for i = 1, math.huge do
    if 0.3 * i ^ 3 - 20 * i ^ 2 - 500 >= 0 then
        print(i)
        break
    end
end

-- $ lua for_number.lua
-- 68

注意:

  1. 在循环开始前,三个表达式都会运行一次。
  2. 控制变量是被for语句自动声明的变量,且其作用范围仅限于循环体内。
  3. 不能随意改变控制变量的值,否则可能会产生随机后果。

泛型for

泛型for遍历迭代函数返回的所有制。

待补充

break、return和goto

break用于从当前的循环结构中跳出,return用于退出函数并返回函数的执行结果,goto用于在函数内跳转到其他位置。

所有函数的最后都有一个隐含的return,因此不需要在没有返回值的函数最后带上return语句。

return只能是代码块的最后一条语句。常用位置是elseend以及until之前的最后一句。return之后的语句不会被执行。

goto语句用于将函数的执行点跳转到相应的标签处。goto语句后面需要紧跟标签名。

标签名的规则形如:::lable::,标识符的前后均有两个冒号。

在进行goto跳转时有一些限制:

  1. 不能直接跳转到一个代码中的标签,代码块中的标签对外不可见。
  2. 不能跳转到函数外。
  3. 不能跳转到局部变量作用域。局部变量作用域指的是从定义到代码块结尾,不能跳转的原因在于是可能存在变量未初始化。
do
    local y = 20
    ::inner_label::
    print(y)
end

goto inner_label  -- 这是不允许的,因为跳转点在局部变量 y 的作用域内

注意:局部变量的作用域终止于声明变量的代码块中的最后一个有效语句处,标签被认为是无效语句

while some_condition do
    if some_condition then goto continue end
    local var = something
    some code
    ::continue:: -- var变量的作用域不包括这里,continue标签在代码块的最后一个有效语句后
end