语句块是一个语句序列,它们会按次序执行:

Lua 支持 空语句,你可以用分号分割语句,也可以以分号开始一个语句块,或是连着写两个分号:

    函数调用和赋值语句都可能以一个小括号打头,这可能让 Lua 的语法产生歧义。我们来看看下面的代码片断:

    1. a = b + c
    2. (print or io.write)('done')

    从语法上说,可能有两种解释方式:

    1. a = b + c(print or io.write)('done')
    2.  
    3. a = b + c; (print or io.write)('done')

    当前的解析器总是用第一种结构来解析,它会将开括号看成函数调用的参数传递开始处。为了避免这种二义性,在一条语句以小括号开头时,前面放一个分号是个好习惯:

    1. ;(print or io.write)('done')

    一个语句块可以被显式的定界为单条语句:

    1. stat ::= do block end

    显式的对一个块定界通常用来控制内部变量声明的作用域。有时,显式定界也用于在一个语句块中间插入return (参见 )。

    3.3.2 – 代码块

    Lua 的一个编译单元被称为一个 代码块。从句法构成上讲,一个代码块就是一个语句块。

    1. chunk ::= block

    Lua 把一个代码块当作一个拥有不定参数的匿名函数(参见)来处理。正是这样,代码块内可以定义局部变量,它可以接收参数,返回若干值。此外,这个匿名函数在编译时还为它的作用域绑定了一个外部局部变量 (参见 §2.2)。该函数总是把 _ENV 作为它唯一的一个上值,即使这个函数不使用这个变量,它也存在。

    代码块可以被保存在文件中,也可以作为宿主程序内部的一个字符串。要执行一个代码块,首先要让 Lua 加载 它,将代码块中的代码预编译成虚拟机中的指令,而后,Lua 用虚拟机解释器来运行编译后的代码。

    代码块可以被预编译为二进制形式;参见程序 luac 以及函数 可获得更多细节。用源码表示的程序和编译后的形式可自由替换;Lua 会自动检测文件格式做相应的处理(参见 load)。

    Lua 允许多重赋值。因此,赋值的语法定义是等号左边放一个变量列表, 而等号右边放一个表达式列表。两边的列表中的元素都用逗号间开:

    表达式放在 中讨论。

    在作赋值操作之前,那值列表会被 调整 为左边变量列表的个数。如果值比需要的更多的话,多余的值就被扔掉。 如果值的数量不够需求,将会按所需扩展若干个 nil。如果表达式列表以一个函数调用结束,这个函数所返回的所有值都会在调整操作之前被置入值列表中(除非这个函数调用被用括号括了起来;参见 §3.4)。

    1. i = 3
    2. i, a[i] = i+1, 20

    会把 a[3] 设置为 20,而不会影响到 a[4] 。这是因为 a[i] 中的 i 在被赋值为 4 之前就被计算出来了(当时是 3 )。 简单说 ,这样一行

    1. x, y = y, x

    会交换 和 y 的值,及

    1. x, y, z = y, z, x

    会轮换 xyz 的值。

    对全局变量以及表的域的赋值操作的含义可以通过元表来改变。对 t[i] = val 这样的变量索引赋值,等价于 settable_event(t,i,val)。(关于函数 settable_event 的详细说明,参见。这个函数并没有在 Lua 中定义出来,也不可以被调用。这里我们列出来,仅仅出于方便解释的目的。)

    对于全局变量 x = val 的赋值等价于(参见 §2.2)。

    3.3.4 – 控制结构

    if, while, and repeat这些控制结构符合通常的意义,而且也有类似的语法:

    1. stat ::= while exp do block end
    2. stat ::= repeat block until exp
    3. stat ::= if exp then block {elseif exp then block} [else block] end

    Lua 也有一个 for 语句,它有两种形式(参见 §3.3.5)。

    控制结构中的条件表达式可以返回任何值。falsenil 两者都被认为是假。所有不同于 nilfalse 的其它值都被认为是真(特别需要注意的是,数字 0 和空字符串也被认为是真)。

    repeatuntil 循环中,内部语句块的结束点不是在 until 这个关键字处,它还包括了其后的条件表达式。因此,条件表达式中可以使用循环内部语句块中的定义的局部变量。

    goto 语句将程序的控制点转移到一个标签处。由于句法上的原因,Lua 里的标签也被认为是语句:

    1. stat ::= goto Name
    2. stat ::= label
    3. label ::= :: Name ::

    除了在内嵌函数中,以及在内嵌语句块中定义了同名标签,的情况外,标签对于它定义所在的整个语句块可见。只要 goto 没有进入一个新的局部变量的作用域,它可以跳转到任意可见标签处。

    标签和没有内容的语句被称为空语句,它们不做任何操作。

    break 被用来结束whilerepeat、或 for 循环,它将跳到循环外接着之后的语句运行:

      break 跳出最内层的循环。

      return 只能被写在一个语句块的最后一句。如果你真的需要从语句块的中间 return,你可以使用显式的定义一个内部语句块,一般写作 do return end。可以这样写是因为现在 return 成了(内部)语句块的最后一句了。

      for 有两种形式:一种是数字形式,另一种是通用形式。

      数字形式的 for 循环,通过一个数学运算不断地运行内部的代码块。下面是它的语法:

      1. stat ::= for Name = exp , exp [‘, exp] do block end

      block 将把 name 作循环变量。从第一个 exp 开始起,直到第二个 exp 的值为止,其步长为第三个 exp 。更确切的说,一个 for 循环看起来是这个样子

      1. for v = e1, e2, e3 do block end

      这等价于代码:

      1. do
      2. local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3)
      3. if not (var and limit and step) then error() end
      4. var = var - step
      5. while true do
      6. var = var + step
      7. if (step >= 0 and var > limit) or (step < 0 and var < limit) then
      8. break
      9. end
      10. local v = var
      11. block
      12. end
      13. end

      注意下面这几点:

      • 所有三个控制表达式都只被运算一次,表达式的计算在循环开始之前。 这些表达式的结果必须是数字。
      • varlimit,以及 step都是一些不可见的变量。 这里给它们起的名字都仅仅用于解释方便。
      • 如果第三个表达式(步长)没有给出,会把步长设为 1 。
      • 循环变量 v 是一个循环内部的局部变量;如果你需要在循环结束后使用这个值,在退出循环前把它赋给另一个变量。
        通用形式的 for 通过一个叫作 迭代器 的函数工作。每次迭代,迭代器函数都会被调用以产生一个新的值,当这个值为 nil 时,循环停止。 通用形式的 for 循环的语法如下:
      1. stat ::= for namelist in explist do block end
      2. namelist ::= Name {‘, Name}

      这样的 for 语句

      1. for var_1, ···, var_n in explist do block end

      它等价于这样一段代码:

      1. do
      2. local f, s, var = explist
      3. while true do
      4. local var_1, ···, var_n = f(s, var)
      5. if var_1 == nil then break end
      6. var = var_1
      7. block
      8. end
      9. end

      注意以下几点:

      • explist 只会被计算一次。它返回三个值, 一个 迭代器 函数,一个 状态,一个 迭代器的初始值
      • fs,与 都是不可见的变量。这里给它们起的名字都只是为了解说方便。
      • 你可以使用 break 来跳出 for 循环。
      • 环变量 var_i 对于循环来说是一个局部变量;你不可以在 for 循环结束后继续使用。如果你需要保留这些值,那么就在循环跳出或结束前赋值到别的变量里去。

      3.3.6 – 函数调用语句

      为了允许使用函数的副作用,函数调用可以被作为一个语句执行:

      在这种情况下,所有的返回值都被舍弃。函数调用在 §3.4.10 中解释。

      局部变量可以在语句块中任何地方声明。 声明可以包含一个初始化赋值操作:

      1. stat ::= local namelist [‘= explist]

      如果有初始化值的话,初始化赋值操作的语法和赋值操作一致(参见 )。若没有初始化值,所有的变量都被初始化为 nil

      一个代码块同时也是一个语句块(参见 §3.3.2),所以局部变量可以放在代码块中那些显式注明的语句块之外。