3 – 语言
37 分钟阅读
3 – The Language – 语言
This section describes the lexis, the syntax, and the semantics of Lua. In other words, this section describes which tokens are valid, how they can be combined, and what their combinations mean.
本节介绍 Lua 的词法、语法和语义。换句话说,本节介绍哪些标记有效,如何组合这些标记,以及它们的组合意味着什么。
Language constructs will be explained using the usual extended BNF notation, in which {a} means 0 or more a’s, and [a] means an optional a. Non-terminals are shown like non-terminal, keywords are shown like kword, and other terminal symbols are shown like ‘=’. The complete syntax of Lua can be found in §9 at the end of this manual.
语言结构将使用通常的扩展 BNF 符号进行解释,其中 {a} 表示 0 个或多个 a,[a] 表示一个可选的 a。非终结符显示为 non-terminal,关键字显示为 kword,其他终结符显示为“=”。Lua 的完整语法可以在本手册末尾的 §9 中找到。
3.1 – Lexical Conventions 词法约定
Lua is a free-form language. It ignores spaces and comments between lexical elements (tokens), except as delimiters between two tokens. In source code, Lua recognizes as spaces the standard ASCII whitespace characters space, form feed, newline, carriage return, horizontal tab, and vertical tab.
Lua 是一种自由格式语言。它忽略词法元素(标记)之间的空格和注释,但作为两个标记之间的分隔符除外。在源代码中,Lua 将标准 ASCII 空白字符空格、换页符、换行符、回车符、水平制表符和垂直制表符识别为空格。
Names (also called identifiers) in Lua can be any string of Latin letters, Arabic-Indic digits, and underscores, not beginning with a digit and not being a reserved word. Identifiers are used to name variables, table fields, and labels.
Lua 中的名称(也称为标识符)可以是任何拉丁字母、阿拉伯-印度数字和下划线的字符串,不能以数字开头,也不能是保留字。标识符用于命名变量、表字段和标签。
The following keywords are reserved and cannot be used as names:
以下关键字是保留字,不能用作名称:
and break do else elseif end
false for function goto if in
local nil not or repeat return
then true until while
Lua is a case-sensitive language: and
is a reserved word, but And
and AND
are two different, valid names. As a convention, programs should avoid creating names that start with an underscore followed by one or more uppercase letters (such as _VERSION
).
Lua 是一种区分大小写的语言: and
是一个保留字,但 And
和 AND
是两个不同的有效名称。按照惯例,程序应避免创建以一个下划线后跟一个或多个大写字母开头的名称(例如 _VERSION
)。
The following strings denote other tokens:
以下字符串表示其他标记:
+ - * / % ^ #
& ~ | << >> //
== ~= <= >= < > =
( ) { } [ ] ::
; : , . .. ...
A short literal string can be delimited by matching single or double quotes, and can contain the following C-like escape sequences: ‘\a
’ (bell), ‘\b
’ (backspace), ‘\f
’ (form feed), ‘\n
’ (newline), ‘\r
’ (carriage return), ‘\t
’ (horizontal tab), ‘\v
’ (vertical tab), ‘\\
’ (backslash), ‘\"
’ (quotation mark [double quote]), and ‘\'
’ (apostrophe [single quote]). A backslash followed by a line break results in a newline in the string. The escape sequence ‘\z
’ skips the following span of whitespace characters, including line breaks; it is particularly useful to break and indent a long literal string into multiple lines without adding the newlines and spaces into the string contents. A short literal string cannot contain unescaped line breaks nor escapes not forming a valid escape sequence.
短文本字符串可以用匹配的单引号或双引号分隔,并且可以包含以下 C 式转义序列:’ \a
‘(响铃)、’ \b
‘(退格)、’ \f
‘(换页)、’ \n
‘(换行)、’ \r
‘(回车)、’ \t
‘(水平制表符)、’ \v
‘(垂直制表符)、’ \\
‘(反斜杠)、’ \"
‘(引号 [双引号])和 ’ \'
‘(撇号 [单引号])。反斜杠后跟换行符会导致字符串中出现换行符。转义序列 ’ \z
’ 会跳过以下空格字符(包括换行符);它特别适用于将长文本字符串拆分并缩进为多行,而无需将换行符和空格添加到字符串内容中。短文本字符串不能包含未转义的换行符或未形成有效转义序列的转义符。
We can specify any byte in a short literal string, including embedded zeros, by its numeric value. This can be done with the escape sequence \x*XX*
, where XX is a sequence of exactly two hexadecimal digits, or with the escape sequence \*ddd*
, where ddd is a sequence of up to three decimal digits. (Note that if a decimal escape sequence is to be followed by a digit, it must be expressed using exactly three digits.)
我们可以通过其数字值指定短字符串中的任何字节,包括嵌入的零。这可以通过转义序列 \x*XX*
来完成,其中 XX 是恰好两个十六进制数字的序列,或者通过转义序列 \*ddd*
来完成,其中 ddd 是最多三个十进制数字的序列。(请注意,如果十进制转义序列后跟一个数字,则必须使用恰好三个数字来表示。)
The UTF-8 encoding of a Unicode character can be inserted in a literal string with the escape sequence \u{*XXX*}
(with mandatory enclosing braces), where XXX is a sequence of one or more hexadecimal digits representing the character code point. This code point can be any value less than 231. (Lua uses the original UTF-8 specification here, which is not restricted to valid Unicode code points.)
Unicode 字符的 UTF-8 编码可以使用转义序列 \u{*XXX*}
(必须用大括号括起来)插入到字符串文字中,其中 XXX 是一个或多个十六进制数字的序列,表示字符代码点。此代码点可以是小于 2 31 的任何值。(Lua 在此处使用原始 UTF-8 规范,该规范不限于有效的 Unicode 代码点。)
Literal strings can also be defined using a long format enclosed by long brackets. We define an opening long bracket of level *n* as an opening square bracket followed by n equal signs followed by another opening square bracket. So, an opening long bracket of level 0 is written as [[
, an opening long bracket of level 1 is written as [=[
, and so on. A closing long bracket is defined similarly; for instance, a closing long bracket of level 4 is written as ]====]
. A long literal starts with an opening long bracket of any level and ends at the first closing long bracket of the same level. It can contain any text except a closing bracket of the same level. Literals in this bracketed form can run for several lines, do not interpret any escape sequences, and ignore long brackets of any other level. Any kind of end-of-line sequence (carriage return, newline, carriage return followed by newline, or newline followed by carriage return) is converted to a simple newline. When the opening long bracket is immediately followed by a newline, the newline is not included in the string.
文字字符串也可以使用长格式定义,用长括号括起来。我们将 n 级开长括号定义为一个开方括号,后跟 n 个等号,再后跟另一个开方括号。因此,0 级开长括号写为 [[
,1 级开长括号写为 [=[
,依此类推。闭长括号的定义类似;例如,4 级闭长括号写为 ]====]
。长文字字符串以任意级别的开长括号开头,并在同级别的第一个闭长括号处结束。它可以包含除同级别闭括号之外的任何文本。这种括号形式的文字字符串可以跨多行,不解释任何转义序列,并忽略任何其他级别的长括号。任何类型的行尾序列(回车、换行、回车后跟换行或换行后跟回车)都会转换为简单的换行。当开长括号后立即跟换行时,换行不包含在字符串中。
As an example, in a system using ASCII (in which ‘a
’ is coded as 97, newline is coded as 10, and ‘1
’ is coded as 49), the five literal strings below denote the same string:
例如,在一个使用 ASCII(其中“ a
”编码为 97,换行符编码为 10,“ 1
”编码为 49)的系统中,以下五个字符串字面量表示相同的字符串:
a = 'alo\n123"'
a = "alo\n123\""
a = '\97lo\10\04923"'
a = [[alo
123"]]
a = [==[
alo
123"]==]
Any byte in a literal string not explicitly affected by the previous rules represents itself. However, Lua opens files for parsing in text mode, and the system’s file functions may have problems with some control characters. So, it is safer to represent binary data as a quoted literal with explicit escape sequences for the non-text characters.
任何字节在文字串中未明确受到前述规则影响时,都代表它自身。然而,Lua 以文本模式打开文件进行解析,并且系统文件函数可能会遇到一些控制字符的问题。因此,最好将二进制数据表示为带引号的文字,并为非文本字符使用明确的转义序列。
A numeric constant (or numeral) can be written with an optional fractional part and an optional decimal exponent, marked by a letter ‘e
’ or ‘E
’. Lua also accepts hexadecimal constants, which start with 0x
or 0X
. Hexadecimal constants also accept an optional fractional part plus an optional binary exponent, marked by a letter ‘p
’ or ‘P
’ and written in decimal. (For instance, 0x1.fp10
denotes 1984, which is 0x1f / 16 multiplied by 210.)
数字常量(或数字)可以写成带可选分数部分和可选十进制指数的形式,用字母“ e
”或“ E
”标记。Lua 也接受十六进制常量,以 0x
或 0X
开头。十六进制常量也接受可选分数部分加上可选二进制指数,用字母“ p
”或“ P
”标记,并以十进制形式书写。(例如, 0x1.fp10
表示 1984,即 0x1f / 16 乘以 2 10 。)
A numeric constant with a radix point or an exponent denotes a float; otherwise, if its value fits in an integer or it is a hexadecimal constant, it denotes an integer; otherwise (that is, a decimal integer numeral that overflows), it denotes a float. Hexadecimal numerals with neither a radix point nor an exponent always denote an integer value; if the value overflows, it wraps around to fit into a valid integer.
带有基点或指数的数字常量表示浮点数;否则,如果其值适合整数或它是十六进制常量,则表示整数;否则(即,溢出的十进制整数数字),则表示浮点数。既没有基点也没有指数的十六进制数字始终表示整数值;如果值溢出,则会环绕以适合有效的整数。
Examples of valid integer constants are
有效整数常量的示例为
3 345 0xff 0xBEBADA
Examples of valid float constants are
有效浮点常量的示例为
3.0 3.1416 314.16e-2 0.31416E1 34e1
0x0.1E 0xA23p-4 0X1.921FB54442D18P+1
A comment starts with a double hyphen (--
) anywhere outside a string. If the text immediately after --
is not an opening long bracket, the comment is a short comment, which runs until the end of the line. Otherwise, it is a long comment, which runs until the corresponding closing long bracket.
注释以双连字符 ( --
) 开头,位于字符串外部的任意位置。如果紧跟在 --
之后的文本不是一个左长括号,则该注释为短注释,一直持续到该行的末尾。否则,它是一个长注释,一直持续到相应的右长括号。
3.2 – Variables 变量
Variables are places that store values. There are three kinds of variables in Lua: global variables, local variables, and table fields.
变量是存储值的位置。Lua 中有三种变量:全局变量、局部变量和表字段。
A single name can denote a global variable or a local variable (or a function’s formal parameter, which is a particular kind of local variable):
单个名称可以表示全局变量或局部变量(或函数的形式参数,它是一种特殊的局部变量):
var ::= Name
Name denotes identifiers (see §3.1).
Name 表示标识符(请参阅 §3.1)。
Any variable name is assumed to be global unless explicitly declared as a local (see §3.3.7). Local variables are lexically scoped: local variables can be freely accessed by functions defined inside their scope (see §3.5).
任何变量名称都假定为全局变量,除非明确声明为局部变量(请参阅 §3.3.7)。局部变量具有词法作用域:局部变量可以被其作用域内定义的函数自由访问(请参阅 §3.5)。
Before the first assignment to a variable, its value is nil.
在首次将值赋给变量之前,其值为 nil。
Square brackets are used to index a table:
方括号用于索引表:
var ::= prefixexp ‘[’ exp ‘]’
The meaning of accesses to table fields can be changed via metatables (see §2.4).
表字段的访问含义可以通过元表来改变(参见 §2.4)。
The syntax var.Name
is just syntactic sugar for var["Name"]
:
语法 var.Name
只是 var["Name"]
的语法糖:
var ::= prefixexp ‘.’ Name
An access to a global variable x
is equivalent to _ENV.x
. Due to the way that chunks are compiled, the variable _ENV
itself is never global (see §2.2).
对全局变量 x
的访问等同于 _ENV.x
。由于块的编译方式,变量 _ENV
本身永远不是全局的(参见 §2.2)。
3.3 – Statements 语句
Lua supports an almost conventional set of statements, similar to those in other conventional languages. This set includes blocks, assignments, control structures, function calls, and variable declarations.
Lua 支持一组几乎传统的语句,类似于其他传统语言中的语句。这组语句包括块、赋值、控制结构、函数调用和变量声明。
3.3.1 – Blocks 3.3.1 – 块
A block is a list of statements, which are executed sequentially:
块是一系列语句,这些语句按顺序执行:
block ::= {stat}
Lua has empty statements that allow you to separate statements with semicolons, start a block with a semicolon or write two semicolons in sequence:
Lua 有空语句,允许你用分号分隔语句,用分号开始一个块或连续写两个分号:
stat ::= ‘;’
Both function calls and assignments can start with an open parenthesis. This possibility leads to an ambiguity in Lua’s grammar. Consider the following fragment:
函数调用和赋值都可以以一个左括号开头。这种可能性导致了 Lua 语法中的歧义。考虑以下片段:
a = b + c
(print or io.write)('done')
The grammar could see this fragment in two ways:
语法可以以两种方式看待此片段:
a = b + c(print or io.write)('done')
The current parser always sees such constructions in the first way, interpreting the open parenthesis as the start of the arguments to a call. To avoid this ambiguity, it is a good practice to always precede with a semicolon statements that start with a parenthesis:
当前解析器总是以第一种方式看待此类结构,将左括号解释为对调用的参数的开始。为了避免这种歧义,最好始终在以括号开头的语句前加上分号:
;(print or io.write)('done')
A block can be explicitly delimited to produce a single statement:
可以明确地定界一个块以生成一条语句:
stat ::= do block end
Explicit blocks are useful to control the scope of variable declarations. Explicit blocks are also sometimes used to add a return statement in the middle of another block (see §3.3.4).
显式块对于控制变量声明的范围很有用。显式块有时也用于在另一个块的中间添加 return 语句(参见 §3.3.4)。
3.3.2 – Chunks 3.3.2 – 块
The unit of compilation of Lua is called a chunk. Syntactically, a chunk is simply a block:
Lua 的编译单元称为块。从语法上讲,块只是一个块:
chunk ::= block
Lua handles a chunk as the body of an anonymous function with a variable number of arguments (see §3.4.11). As such, chunks can define local variables, receive arguments, and return values. Moreover, such anonymous function is compiled as in the scope of an external local variable called _ENV
(see §2.2). The resulting function always has _ENV
as its only external variable, even if it does not use that variable.
Lua 将块作为具有可变数量参数的匿名函数的主体(参见 §3.4.11)。因此,块可以定义局部变量、接收参数和返回值。此外,此类匿名函数在名为 _ENV
的外部局部变量的范围内编译(参见 §2.2)。即使结果函数不使用该变量,它也始终将 _ENV
作为其唯一的外部变量。
A chunk can be stored in a file or in a string inside the host program. To execute a chunk, Lua first loads it, precompiling the chunk’s code into instructions for a virtual machine, and then Lua executes the compiled code with an interpreter for the virtual machine.
块可以存储在文件中或宿主程序内的字符串中。要执行块,Lua 首先加载它,将块的代码预编译为虚拟机的指令,然后 Lua 使用虚拟机的解释器执行已编译的代码。
Chunks can also be precompiled into binary form; see the program luac
and the function string.dump
for details. Programs in source and compiled forms are interchangeable; Lua automatically detects the file type and acts accordingly (see load
).
块也可以预编译成二进制形式;有关详细信息,请参阅程序 luac
和函数 string.dump
。源代码和编译形式的程序是可互换的;Lua 会自动检测文件类型并采取相应的操作(请参阅 load
)。
3.3.3 – Assignment 3.3.3 – 赋值
Lua allows multiple assignments. Therefore, the syntax for assignment defines a list of variables on the left side and a list of expressions on the right side. The elements in both lists are separated by commas:
Lua 允许进行多重赋值。因此,赋值的语法在左侧定义了一个变量列表,在右侧定义了一个表达式列表。两个列表中的元素都用逗号分隔:
stat ::= varlist ‘=’ explist
varlist ::= var {‘,’ var}
explist ::= exp {‘,’ exp}
Expressions are discussed in §3.4.
表达式在 §3.4 中讨论。
Before the assignment, the list of values is adjusted to the length of the list of variables (see §3.4.12).
在赋值之前,值列表将调整为变量列表的长度(参见 §3.4.12)。
If a variable is both assigned and read inside a multiple assignment, Lua ensures that all reads get the value of the variable before the assignment. Thus the code
如果一个变量在多重赋值中既被赋值又被读取,Lua 确保所有读取在赋值之前获取变量的值。因此代码
i = 3
i, a[i] = i+1, 20
sets a[3]
to 20, without affecting a[4]
because the i
in a[i]
is evaluated (to 3) before it is assigned 4. Similarly, the line
将 a[3]
设置为 20,而不影响 a[4]
,因为 a[i]
中的 i
在被赋值为 4 之前被计算(为 3)。类似地,行
x, y = y, x
exchanges the values of x
and y
, and
交换 x
和 y
的值,而
x, y, z = y, z, x
cyclically permutes the values of x
, y
, and z
.
循环排列 x
、 y
和 z
的值。
Note that this guarantee covers only accesses syntactically inside the assignment statement. If a function or a metamethod called during the assignment changes the value of a variable, Lua gives no guarantees about the order of that access.
请注意,此保证仅涵盖赋值语句中语法上的访问。如果在赋值期间调用的函数或元方法更改了变量的值,Lua 无法保证该访问的顺序。
An assignment to a global name x = val
is equivalent to the assignment _ENV.x = val
(see §2.2).
对全局名称 x = val
的赋值等同于赋值 _ENV.x = val
(请参阅 §2.2)。
The meaning of assignments to table fields and global variables (which are actually table fields, too) can be changed via metatables (see §2.4).
可以通过元表(请参阅 §2.4)更改对表字段和全局变量(实际上也是表字段)的赋值的含义。
3.3.4 – Control Structures 3.3.4 – 控制结构
The control structures if, while, and repeat have the usual meaning and familiar syntax:
控制结构 if、while 和 repeat 具有通常的含义和熟悉的语法:
stat ::= while exp do block end
stat ::= repeat block until exp
stat ::= if exp then block {elseif exp then block} [else block] end
Lua also has a for statement, in two flavors (see §3.3.5).
Lua 还具有 for 语句,分为两种类型(请参阅 §3.3.5)。
The condition expression of a control structure can return any value. Both false and nil test false. All values different from nil and false test true. In particular, the number 0 and the empty string also test true.
控制结构的条件表达式可以返回任何值。false 和 nil 都测试为 false。所有不同于 nil 和 false 的值都测试为 true。特别是,数字 0 和空字符串也测试为 true。
In the repeat–until loop, the inner block does not end at the until keyword, but only after the condition. So, the condition can refer to local variables declared inside the loop block.
在 repeat–until 循环中,内部块并不在 until 关键字处结束,而是在条件之后才结束。因此,条件可以引用在循环块内声明的局部变量。
The goto statement transfers the program control to a label. For syntactical reasons, labels in Lua are considered statements too:
goto 语句将程序控制权转移到一个标签。出于语法原因,Lua 中的标签也被视为语句:
stat ::= goto Name
stat ::= label
label ::= ‘::’ Name ‘::’
A label is visible in the entire block where it is defined, except inside nested functions. A goto may jump to any visible label as long as it does not enter into the scope of a local variable. A label should not be declared where a label with the same name is visible, even if this other label has been declared in an enclosing block.
标签在其定义的整个块中可见,嵌套函数内部除外。goto 可以跳转到任何可见标签,只要它不进入局部变量的范围。不应在可见同名标签处声明标签,即使此其他标签已在封闭块中声明。
The break statement terminates the execution of a while, repeat, or for loop, skipping to the next statement after the loop:
break 语句终止 while、repeat 或 for 循环的执行,跳到循环后的下一条语句:
stat ::= break
A break ends the innermost enclosing loop.
break 结束最内层封闭循环。
The return statement is used to return values from a function or a chunk (which is handled as an anonymous function). Functions can return more than one value, so the syntax for the return statement is
return 语句用于从函数或块(作为匿名函数处理)返回值。函数可以返回多个值,因此 return 语句的语法为
stat ::= return [explist] [‘;’]
The return statement can only be written as the last statement of a block. If it is necessary to return in the middle of a block, then an explicit inner block can be used, as in the idiom do return end
, because now return is the last statement in its (inner) block.
return 语句只能写为块的最后一条语句。如果需要在块中间返回,则可以使用显式内部块,如惯用语 do return end
中所示,因为现在 return 是其(内部)块中的最后一条语句。
3.3.5 – For Statement 3.3.5 – For 语句
The for statement has two forms: one numerical and one generic.
for 语句有两种形式:一种是数字形式,另一种是通用形式。 数字 for 循环
The numerical for loop
The numerical for loop repeats a block of code while a control variable goes through an arithmetic progression. It has the following syntax:
数值 for 循环在控制变量经历算术级数时重复一个代码块。它具有以下语法:
stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end
The given identifier (Name) defines the control variable, which is a new variable local to the loop body (block).
给定的标识符 (Name) 定义控制变量,它是循环体 (block) 的局部新变量。
The loop starts by evaluating once the three control expressions. Their values are called respectively the initial value, the limit, and the step. If the step is absent, it defaults to 1.
循环首先对三个控制表达式求值一次。它们的值分别称为初始值、限制和步长。如果缺少步长,则默认为 1。
If both the initial value and the step are integers, the loop is done with integers; note that the limit may not be an integer. Otherwise, the three values are converted to floats and the loop is done with floats. Beware of floating-point accuracy in this case.
如果初始值和步长都是整数,则循环使用整数完成;请注意,限制可能不是整数。否则,三个值将转换为浮点数,循环将使用浮点数完成。在这种情况下,请注意浮点精度。
After that initialization, the loop body is repeated with the value of the control variable going through an arithmetic progression, starting at the initial value, with a common difference given by the step. A negative step makes a decreasing sequence; a step equal to zero raises an error. The loop continues while the value is less than or equal to the limit (greater than or equal to for a negative step). If the initial value is already greater than the limit (or less than, if the step is negative), the body is not executed.
在该初始化之后,循环体将重复执行,控制变量的值将经历一个算术级数,从初始值开始,公差由步长给出。负步长会产生一个递减序列;步长等于零会引发错误。循环将持续到该值小于或等于限制(对于负步长,则大于或等于)。如果初始值已经大于限制(或小于,如果步长为负),则不会执行主体。
For integer loops, the control variable never wraps around; instead, the loop ends in case of an overflow.
对于整数循环,控制变量永远不会环绕;相反,在发生溢出时循环结束。
You should not change the value of the control variable during the loop. If you need its value after the loop, assign it to another variable before exiting the loop.
您不应在循环期间更改控制变量的值。如果您需要循环后的值,请在退出循环之前将其分配给另一个变量。
The generic for loop 通用 for 循环
The generic for statement works over functions, called iterators. On each iteration, the iterator function is called to produce a new value, stopping when this new value is nil. The generic for loop has the following syntax:
通用 for 语句适用于称为迭代器的函数。在每次迭代中,都会调用迭代器函数以生成一个新值,当此新值为 nil 时停止。通用 for 循环具有以下语法:
stat ::= for namelist in explist do block end
namelist ::= Name {‘,’ Name}
A for statement like
类似于以下内容的 for 语句
for var_1, ···, var_n in explist do body end
works as follows.
如下所示。
The names var_i declare loop variables local to the loop body. The first of these variables is the control variable.
名称 var_i 声明循环变量,这些变量为循环体局部所有。第一个变量是控制变量。
The loop starts by evaluating explist to produce four values: an iterator function, a state, an initial value for the control variable, and a closing value.
循环首先通过计算 explist 来生成四个值:一个迭代器函数、一个状态、控制变量的初始值和一个结束值。
Then, at each iteration, Lua calls the iterator function with two arguments: the state and the control variable. The results from this call are then assigned to the loop variables, following the rules of multiple assignments (see §3.3.3). If the control variable becomes nil, the loop terminates. Otherwise, the body is executed and the loop goes to the next iteration.
然后,在每次迭代中,Lua 使用两个参数调用迭代器函数:状态和控制变量。然后将此调用的结果分配给循环变量,遵循多重赋值的规则(参见 §3.3.3)。如果控制变量变为 nil,则循环终止。否则,执行主体,循环转到下一次迭代。
The closing value behaves like a to-be-closed variable (see §3.3.8), which can be used to release resources when the loop ends. Otherwise, it does not interfere with the loop.
结束值的行为类似于待关闭变量(参见 §3.3.8),可用于在循环结束时释放资源。否则,它不会干扰循环。
You should not change the value of the control variable during the loop.
您不应在循环期间更改控制变量的值。
3.3.6 – Function Calls as Statements 3.3.6 – 函数调用作为语句
To allow possible side-effects, function calls can be executed as statements:
为了允许可能的副作用,可以将函数调用作为语句执行:
stat ::= functioncall
In this case, all returned values are thrown away. Function calls are explained in §3.4.10.
在这种情况下,所有返回的值都会被丢弃。§3.4.10 中解释了函数调用。
3.3.7 – Local Declarations 3.3.7 – 局部声明
Local variables can be declared anywhere inside a block. The declaration can include an initialization:
可以在块内的任何位置声明局部变量。声明可以包括初始化:
stat ::= local attnamelist [‘=’ explist]
attnamelist ::= Name attrib {‘,’ Name attrib}
If present, an initial assignment has the same semantics of a multiple assignment (see §3.3.3). Otherwise, all variables are initialized with nil.
如果存在,初始赋值具有与多重赋值相同的语义(参见 §3.3.3)。否则,所有变量都初始化为 nil。
Each variable name may be postfixed by an attribute (a name between angle brackets):
每个变量名都可以后缀一个属性(尖括号中的名称):
attrib ::= [‘<’ Name ‘>’]
There are two possible attributes: const
, which declares a constant variable, that is, a variable that cannot be assigned to after its initialization; and close
, which declares a to-be-closed variable (see §3.3.8). A list of variables can contain at most one to-be-closed variable.
有两个可能的属性: const
,它声明一个常量变量,即一个在初始化后不能被赋值的变量;和 close
,它声明一个待关闭变量(参见 §3.3.8)。变量列表最多可以包含一个待关闭变量。
A chunk is also a block (see §3.3.2), and so local variables can be declared in a chunk outside any explicit block.
块也是一个区块(参见 §3.3.2),因此可以在任何显式区块之外的块中声明局部变量。
The visibility rules for local variables are explained in §3.5.
局部变量的可见性规则在 §3.5 中解释。
3.3.8 – To-be-closed Variables 3.3.8 – 待关闭变量
A to-be-closed variable behaves like a constant local variable, except that its value is closed whenever the variable goes out of scope, including normal block termination, exiting its block by break/goto/return, or exiting by an error.
待关闭变量的行为类似于常量局部变量,但其值会在变量超出范围时关闭,包括正常块终止、通过 break/goto/return 退出块或通过错误退出。
Here, to close a value means to call its __close
metamethod. When calling the metamethod, the value itself is passed as the first argument and the error object that caused the exit (if any) is passed as a second argument; if there was no error, the second argument is nil.
在这里,关闭值意味着调用其 __close
元方法。在调用元方法时,值本身作为第一个参数传递,导致退出的错误对象(如果有)作为第二个参数传递;如果没有错误,则第二个参数为 nil。
The value assigned to a to-be-closed variable must have a __close
metamethod or be a false value. (nil and false are ignored as to-be-closed values.)
分配给待关闭变量的值必须具有 __close
元方法或为假值。(nil 和 false 被忽略为待关闭值。)
If several to-be-closed variables go out of scope at the same event, they are closed in the reverse order that they were declared.
如果在同一事件中有多个待关闭变量超出范围,则它们将按声明的相反顺序关闭。
If there is any error while running a closing method, that error is handled like an error in the regular code where the variable was defined. After an error, the other pending closing methods will still be called.
如果在运行关闭方法时出现任何错误,则该错误将像在定义变量的常规代码中的错误一样处理。在出现错误后,仍将调用其他待处理的关闭方法。
If a coroutine yields and is never resumed again, some variables may never go out of scope, and therefore they will never be closed. (These variables are the ones created inside the coroutine and in scope at the point where the coroutine yielded.) Similarly, if a coroutine ends with an error, it does not unwind its stack, so it does not close any variable. In both cases, you can either use finalizers or call coroutine.close
to close the variables. However, if the coroutine was created through coroutine.wrap
, then its corresponding function will close the coroutine in case of errors.
如果协程让步并且永远不会再次恢复,某些变量可能永远不会超出范围,因此它们永远不会被关闭。(这些变量是在协程内部创建的,并且在协程让步时处于范围内。)同样,如果协程以错误结束,它不会展开其栈,因此它不会关闭任何变量。在这两种情况下,您都可以使用终结器或调用 coroutine.close
来关闭变量。但是,如果协程是通过 coroutine.wrap
创建的,那么其对应的函数将在发生错误时关闭协程。
3.4 – Expressions 表达式
The basic expressions in Lua are the following:
Lua 中的基本表达式如下:
exp ::= prefixexp
exp ::= nil | false | true
exp ::= Numeral
exp ::= LiteralString
exp ::= functiondef
exp ::= tableconstructor
exp ::= ‘...’
exp ::= exp binop exp
exp ::= unop exp
prefixexp ::= var | functioncall | ‘(’ exp ‘)’
Numerals and literal strings are explained in §3.1; variables are explained in §3.2; function definitions are explained in §3.4.11; function calls are explained in §3.4.10; table constructors are explained in §3.4.9. Vararg expressions, denoted by three dots (’...
’), can only be used when directly inside a variadic function; they are explained in §3.4.11.
数字和字符串文字在 §3.1 中进行了解释;变量在 §3.2 中进行了解释;函数定义在 §3.4.11 中进行了解释;函数调用在 §3.4.10 中进行了解释;表构造函数在 §3.4.9 中进行了解释。可变参数表达式,用三个点(“ ...
”)表示,只能在可变参数函数内部直接使用;它们在 §3.4.11 中进行了解释。
Binary operators comprise arithmetic operators (see §3.4.1), bitwise operators (see §3.4.2), relational operators (see §3.4.4), logical operators (see §3.4.5), and the concatenation operator (see §3.4.6). Unary operators comprise the unary minus (see §3.4.1), the unary bitwise NOT (see §3.4.2), the unary logical not (see §3.4.5), and the unary length operator (see §3.4.7).
二元运算符包括算术运算符(见§3.4.1)、按位运算符(见§3.4.2)、关系运算符(见§3.4.4)、逻辑运算符(见§3.4.5)和连接运算符(见§3.4.6)。一元运算符包括一元减号(见§3.4.1)、一元按位非(见§3.4.2)、一元逻辑非(见§3.4.5)和一元长度运算符(见§3.4.7)。
3.4.1 – Arithmetic Operators 3.4.1 – 算术运算符
Lua supports the following arithmetic operators:
Lua 支持以下算术运算符:
+
: addition+
:加法-
: subtraction-
:减法\*
: multiplication*
:乘法/
: float division/
:浮点除法//
: floor division//
:取整除法%
: modulo%
:模运算^
: exponentiation^
:幂运算-
: unary minus-
:一元负号
With the exception of exponentiation and float division, the arithmetic operators work as follows: If both operands are integers, the operation is performed over integers and the result is an integer. Otherwise, if both operands are numbers, then they are converted to floats, the operation is performed following the machine’s rules for floating-point arithmetic (usually the IEEE 754 standard), and the result is a float. (The string library coerces strings to numbers in arithmetic operations; see §3.4.3 for details.)
除指数运算和浮点除法外,算术运算符的工作方式如下:如果两个操作数都是整数,则对整数执行运算,结果为整数。否则,如果两个操作数都是数字,则将它们转换为浮点数,按照机器的浮点运算规则(通常是 IEEE 754 标准)执行运算,结果为浮点数。(字符串库在算术运算中将字符串强制转换为数字;有关详细信息,请参阅 §3.4.3。)
Exponentiation and float division (/
) always convert their operands to floats and the result is always a float. Exponentiation uses the ISO C function pow
, so that it works for non-integer exponents too.
指数运算和浮点除法 ( /
) 始终将操作数转换为浮点数,结果始终为浮点数。指数运算使用 ISO C 函数 pow
,因此它也适用于非整数指数。
Floor division (//
) is a division that rounds the quotient towards minus infinity, resulting in the floor of the division of its operands.
取整除法 ( //
) 是一种将商朝负无穷大方向舍入的除法,结果为其操作数除法的向下取整。
Modulo is defined as the remainder of a division that rounds the quotient towards minus infinity (floor division).
模运算定义为将商朝负无穷大方向舍入的除法的余数(向下取整除法)。
In case of overflows in integer arithmetic, all operations wrap around.
在整数运算中发生溢出时,所有运算都会环绕。
3.4.2 – Bitwise Operators 3.4.2 – 按位运算符
Lua supports the following bitwise operators:
Lua 支持以下按位运算符:
&
: bitwise AND&
:按位与|
: bitwise OR|
:按位或~
: bitwise exclusive OR~
:按位异或>>
: right shift>>
:右移<<
: left shift<<
:左移~
: unary bitwise NOT~
:一元按位非
All bitwise operations convert its operands to integers (see §3.4.3), operate on all bits of those integers, and result in an integer.
所有按位运算都会将其操作数转换为整数(参见 §3.4.3),对这些整数的所有位进行运算,并生成一个整数。
Both right and left shifts fill the vacant bits with zeros. Negative displacements shift to the other direction; displacements with absolute values equal to or higher than the number of bits in an integer result in zero (as all bits are shifted out).
右移和左移都会用零填充空位。负位移向另一个方向移动;绝对值等于或大于整数中位数的位移导致零(因为所有位都被移出)。
3.4.3 – Coercions and Conversions 3.4.3 – 强制转换和转换
Lua provides some automatic conversions between some types and representations at run time. Bitwise operators always convert float operands to integers. Exponentiation and float division always convert integer operands to floats. All other arithmetic operations applied to mixed numbers (integers and floats) convert the integer operand to a float. The C API also converts both integers to floats and floats to integers, as needed. Moreover, string concatenation accepts numbers as arguments, besides strings.
Lua 在运行时提供了一些类型和表示之间的自动转换。按位运算符始终将浮点操作数转换为整数。指数和浮点除法始终将整数操作数转换为浮点数。对混合数字(整数和浮点数)应用的所有其他算术运算都会将整数操作数转换为浮点数。C API 还会根据需要将整数转换为浮点数,并将浮点数转换为整数。此外,除了字符串之外,字符串连接还接受数字作为参数。
In a conversion from integer to float, if the integer value has an exact representation as a float, that is the result. Otherwise, the conversion gets the nearest higher or the nearest lower representable value. This kind of conversion never fails.
在从整数到浮点数的转换中,如果整数值具有浮点数的精确表示,那就是结果。否则,转换将获得最近的高值或最近的低值可表示值。这种转换永远不会失败。
The conversion from float to integer checks whether the float has an exact representation as an integer (that is, the float has an integral value and it is in the range of integer representation). If it does, that representation is the result. Otherwise, the conversion fails.
从浮点数到整数的转换检查浮点数是否具有整数的精确表示(即,浮点数具有整数值并且它在整数表示的范围内)。如果是,则该表示是结果。否则,转换失败。
Several places in Lua coerce strings to numbers when necessary. In particular, the string library sets metamethods that try to coerce strings to numbers in all arithmetic operations. If the conversion fails, the library calls the metamethod of the other operand (if present) or it raises an error. Note that bitwise operators do not do this coercion.
Lua 中的几个地方在必要时将字符串强制转换为数字。特别是,字符串库设置元方法,尝试在所有算术运算中将字符串强制转换为数字。如果转换失败,则库将调用另一个操作数的元方法(如果存在)或引发错误。请注意,按位运算符不会执行此强制转换。
It is always a good practice not to rely on the implicit coercions from strings to numbers, as they are not always applied; in particular, "1"==1
is false and "1"<1
raises an error (see §3.4.4). These coercions exist mainly for compatibility and may be removed in future versions of the language.
最好不要依赖于从字符串到数字的隐式强制转换,因为它们并不总是适用;特别是, "1"==1
为假, "1"<1
引发错误(参见 §3.4.4)。这些强制转换主要出于兼容性而存在,并且可能会在语言的未来版本中删除。
A string is converted to an integer or a float following its syntax and the rules of the Lua lexer. The string may have also leading and trailing whitespaces and a sign. All conversions from strings to numbers accept both a dot and the current locale mark as the radix character. (The Lua lexer, however, accepts only a dot.) If the string is not a valid numeral, the conversion fails. If necessary, the result of this first step is then converted to a specific number subtype following the previous rules for conversions between floats and integers.
字符串按照其语法和 Lua 词法分析器的规则转换为整数或浮点数。字符串还可以具有前导和尾随空格以及符号。从字符串到数字的所有转换都接受点和当前区域标记作为基数字符。(但是,Lua 词法分析器只接受点。)如果字符串不是有效的数字,则转换失败。如有必要,此第一步的结果将按照浮点数和整数之间的转换的先前规则转换为特定的数字子类型。
The conversion from numbers to strings uses a non-specified human-readable format. To convert numbers to strings in any specific way, use the function string.format
.
从数字到字符串的转换使用未指定的人类可读格式。要以任何特定方式将数字转换为字符串,请使用函数 string.format
。
3.4.4 – Relational Operators 3.4.4 – 关系运算符
Lua supports the following relational operators:
Lua 支持以下关系运算符:
==
: equality==
:相等~=
: inequality~=
:不等<
: less than<
:小于>
: greater than>
:大于<=
: less or equal<=
:小于或等于>=
: greater or equal>=
:大于或等于
These operators always result in false or true.
这些运算符始终返回 false 或 true。
Equality (==
) first compares the type of its operands. If the types are different, then the result is false. Otherwise, the values of the operands are compared. Strings are equal if they have the same byte content. Numbers are equal if they denote the same mathematical value.
等式 ( ==
) 首先比较其操作数的类型。如果类型不同,则结果为 false。否则,比较操作数的值。如果字符串具有相同的字节内容,则它们相等。如果数字表示相同的数学值,则它们相等。
Tables, userdata, and threads are compared by reference: two objects are considered equal only if they are the same object. Every time you create a new object (a table, a userdata, or a thread), this new object is different from any previously existing object. A function is always equal to itself. Functions with any detectable difference (different behavior, different definition) are always different. Functions created at different times but with no detectable differences may be classified as equal or not (depending on internal caching details).
表、用户数据和线程通过引用进行比较:只有当两个对象是同一个对象时,才认为它们相等。每次创建新对象(表、用户数据或线程)时,此新对象都不同于任何先前存在的对象。函数始终等于自身。具有任何可检测差异(不同行为、不同定义)的函数始终不同。在不同时间创建但没有可检测差异的函数可以分类为相等或不相等(取决于内部缓存详细信息)。
You can change the way that Lua compares tables and userdata by using the __eq
metamethod (see §2.4).
您可以使用 __eq
元方法更改 Lua 比较表和用户数据的方式(请参阅 §2.4)。
Equality comparisons do not convert strings to numbers or vice versa. Thus, "0"==0
evaluates to false, and t[0]
and t["0"]
denote different entries in a table.
等式比较不会将字符串转换为数字,反之亦然。因此, "0"==0
计算结果为 false,而 t[0]
和 t["0"]
表示表中的不同条目。
The operator ~=
is exactly the negation of equality (==
).
运算符 ~=
正好是相等性的否定 ( ==
)。
The order operators work as follows. If both arguments are numbers, then they are compared according to their mathematical values, regardless of their subtypes. Otherwise, if both arguments are strings, then their values are compared according to the current locale. Otherwise, Lua tries to call the __lt
or the __le
metamethod (see §2.4). A comparison a > b
is translated to b < a
and a >= b
is translated to b <= a
.
顺序运算符的工作方式如下。如果两个参数都是数字,那么它们将根据其数学值进行比较,而不管其子类型如何。否则,如果两个参数都是字符串,那么它们的数值将根据当前区域设置进行比较。否则,Lua 尝试调用 __lt
或 __le
元方法(参见 §2.4)。比较 a > b
转换为 b < a
, a >= b
转换为 b <= a
。
Following the IEEE 754 standard, the special value NaN is considered neither less than, nor equal to, nor greater than any value, including itself.
按照 IEEE 754 标准,特殊值 NaN 被认为既小于、不等于也不大于任何值,包括它自身。
3.4.5 – Logical Operators 3.4.5 – 逻辑运算符
The logical operators in Lua are and, or, and not. Like the control structures (see §3.3.4), all logical operators consider both false and nil as false and anything else as true.
Lua 中的逻辑运算符是 and、or 和 not。与控制结构(参见 §3.3.4)一样,所有逻辑运算符都将 false 和 nil 视为 false,将其他任何内容视为 true。
The negation operator not always returns false or true. The conjunction operator and returns its first argument if this value is false or nil; otherwise, and returns its second argument. The disjunction operator or returns its first argument if this value is different from nil and false; otherwise, or returns its second argument. Both and and or use short-circuit evaluation; that is, the second operand is evaluated only if necessary. Here are some examples:
否定运算符 not 并不总是返回 false 或 true。连接运算符 and 如果该值是 false 或 nil,则返回其第一个参数;否则,and 返回其第二个参数。析取运算符 or 如果该值与 nil 和 false 不同,则返回其第一个参数;否则,or 返回其第二个参数。and 和 or 都使用短路求值;也就是说,仅在必要时才计算第二个操作数。以下是一些示例:
10 or 20 --> 10
10 or error() --> 10
nil or "a" --> "a"
nil and 10 --> nil
false and error() --> false
false and nil --> false
false or nil --> nil
10 and 20 --> 20
3.4.6 – Concatenation 3.4.6 – 连接
The string concatenation operator in Lua is denoted by two dots (’..
’). If both operands are strings or numbers, then the numbers are converted to strings in a non-specified format (see §3.4.3). Otherwise, the __concat
metamethod is called (see §2.4).
Lua 中的字符串连接运算符表示为两个点(’ ..
‘)。如果两个操作数都是字符串或数字,则数字将以非指定格式转换为字符串(参见 §3.4.3)。否则,将调用 __concat
元方法(参见 §2.4)。
3.4.7 – The Length Operator 3.4.7 – 长度运算符
The length operator is denoted by the unary prefix operator #
.
长度运算符表示为一元前缀运算符 #
。
The length of a string is its number of bytes. (That is the usual meaning of string length when each character is one byte.)
字符串的长度是其字节数。(当每个字符一个字节时,这是字符串长度的通常含义。)
The length operator applied on a table returns a border in that table. A border in a table t
is any non-negative integer that satisfies the following condition:
对表应用长度运算符会返回该表中的边框。表 t
中的边框是满足以下条件的任何非负整数:
(border == 0 or t[border] ~= nil) and
(t[border + 1] == nil or border == math.maxinteger)
In words, a border is any positive integer index present in the table that is followed by an absent index, plus two limit cases: zero, when index 1 is absent; and the maximum value for an integer, when that index is present. Note that keys that are not positive integers do not interfere with borders.
换句话说,边框是表中存在的任何正整数索引,后跟一个不存在的索引,加上两个限制情况:零,当索引 1 不存在时;以及整数的最大值,当该索引存在时。请注意,不是正整数的键不会干扰边框。
A table with exactly one border is called a sequence. For instance, the table {10, 20, 30, 40, 50}
is a sequence, as it has only one border (5). The table {10, 20, 30, nil, 50}
has two borders (3 and 5), and therefore it is not a sequence. (The nil at index 4 is called a hole.) The table {nil, 20, 30, nil, nil, 60, nil}
has three borders (0, 3, and 6), so it is not a sequence, too. The table {}
is a sequence with border 0.
只有一个边框的表称为序列。例如,表 {10, 20, 30, 40, 50}
是一个序列,因为它只有一个边框 (5)。表 {10, 20, 30, nil, 50}
有两个边框 (3 和 5),因此它不是序列。(索引 4 处的 nil 称为孔。)表 {nil, 20, 30, nil, nil, 60, nil}
有三个边框 (0、3 和 6),因此它也不是序列。表 {}
是边框为 0 的序列。
When t
is a sequence, #t
returns its only border, which corresponds to the intuitive notion of the length of the sequence. When t
is not a sequence, #t
can return any of its borders. (The exact one depends on details of the internal representation of the table, which in turn can depend on how the table was populated and the memory addresses of its non-numeric keys.)
当 t
是序列时, #t
返回其唯一边框,这对应于序列长度的直观概念。当 t
不是序列时, #t
可以返回其任何边框。(确切的边框取决于表的内部表示的详细信息,而这又取决于表的填充方式及其非数字键的内存地址。)
The computation of the length of a table has a guaranteed worst time of O(log n), where n is the largest integer key in the table.
计算表的长度的最坏时间保证为 O(log n),其中 n 是表中最大的整数键。
A program can modify the behavior of the length operator for any value but strings through the __len
metamethod (see §2.4).
程序可以通过 __len
元方法修改除字符串之外的任何值的长度运算符的行为(参见 §2.4)。
3.4.8 – Precedence 3.4.8 – 优先级
Operator precedence in Lua follows the table below, from lower to higher priority:
Lua 中的运算符优先级遵循下表,从低到高优先级:
or
and
< > <= >= ~= ==
|
~
&
<< >>
..
+ -
* / // %
unary operators (not # - ~)
^
As usual, you can use parentheses to change the precedences of an expression. The concatenation (’..
’) and exponentiation (’^
’) operators are right associative. All other binary operators are left associative.
通常,您可以使用括号来更改表达式的优先级。连接(’ ..
‘)和指数(’ ^
‘)运算符是右结合的。所有其他二元运算符都是左结合的。
3.4.9 – Table Constructors 3.4.9 – 表构造器
Table constructors are expressions that create tables. Every time a constructor is evaluated, a new table is created. A constructor can be used to create an empty table or to create a table and initialize some of its fields. The general syntax for constructors is
表构造器是创建表的表达式。每次计算构造器时,都会创建一个新表。构造器可用于创建空表或创建表并初始化其中的一些字段。构造器的通用语法为
tableconstructor ::= ‘{’ [fieldlist] ‘}’
fieldlist ::= field {fieldsep field} [fieldsep]
field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp
fieldsep ::= ‘,’ | ‘;’
Each field of the form [exp1] = exp2
adds to the new table an entry with key exp1
and value exp2
. A field of the form name = exp
is equivalent to ["name"] = exp
. Fields of the form exp
are equivalent to [i] = exp
, where i
are consecutive integers starting with 1; fields in the other formats do not affect this counting. For example,
表单的每个字段 [exp1] = exp2
向新表中添加一个键为 exp1
、值为 exp2
的条目。形式为 name = exp
的字段等同于 ["name"] = exp
。形式为 exp
的字段等同于 [i] = exp
,其中 i
是从 1 开始的连续整数;其他格式的字段不影响此计数。例如,
a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }
is equivalent to
等同于
do
local t = {}
t[f(1)] = g
t[1] = "x" -- 1st exp
t[2] = "y" -- 2nd exp
t.x = 1 -- t["x"] = 1
t[3] = f(x) -- 3rd exp
t[30] = 23
t[4] = 45 -- 4th exp
a = t
end
The order of the assignments in a constructor is undefined. (This order would be relevant only when there are repeated keys.)
构造函数中赋值的顺序是未定义的。(只有在存在重复键时,此顺序才相关。)
If the last field in the list has the form exp
and the expression is a multires expression, then all values returned by this expression enter the list consecutively (see §3.4.12).
如果列表中的最后一个字段具有 exp
形式,并且表达式是多重表达式,则此表达式返回的所有值连续进入列表(参见 §3.4.12)。
The field list can have an optional trailing separator, as a convenience for machine-generated code.
字段列表可以有一个可选的尾随分隔符,以便于机器生成的代码。
3.4.10 – Function Calls 3.4.10 – 函数调用
A function call in Lua has the following syntax:
Lua 中的函数调用具有以下语法:
functioncall ::= prefixexp args
In a function call, first prefixexp and args are evaluated. If the value of prefixexp has type function, then this function is called with the given arguments. Otherwise, if present, the prefixexp __call
metamethod is called: its first argument is the value of prefixexp, followed by the original call arguments (see §2.4).
在函数调用中,首先计算 prefixexp 和 args。如果 prefixexp 的值具有函数类型,则使用给定的参数调用此函数。否则,如果存在,则调用 prefixexp __call
元方法:它的第一个参数是 prefixexp 的值,后跟原始调用参数(参见 §2.4)。
The form 形式
functioncall ::= prefixexp ‘:’ Name args
can be used to emulate methods. A call v:name(*args*)
is syntactic sugar for v.name(v,*args*)
, except that v
is evaluated only once.
可用于模拟方法。调用 v:name(*args*)
是 v.name(v,*args*)
的语法糖,除了 v
仅计算一次。
Arguments have the following syntax:
参数具有以下语法:
args ::= ‘(’ [explist] ‘)’
args ::= tableconstructor
args ::= LiteralString
All argument expressions are evaluated before the call. A call of the form f{*fields*}
is syntactic sugar for f({*fields*})
; that is, the argument list is a single new table. A call of the form f'*string*'
(or f"*string*"
or f[[*string*]]
) is syntactic sugar for f('*string*')
; that is, the argument list is a single literal string.
在调用之前,所有参数表达式都会被计算。形式为 f{*fields*}
的调用是 f({*fields*})
的语法糖;也就是说,参数列表是一个新的表。形式为 f'*string*'
(或 f"*string*"
或 f[[*string*]]
)的调用是 f('*string*')
的语法糖;也就是说,参数列表是一个字符串字面量。
A call of the form return *functioncall*
not in the scope of a to-be-closed variable is called a tail call. Lua implements proper tail calls (or proper tail recursion): In a tail call, the called function reuses the stack entry of the calling function. Therefore, there is no limit on the number of nested tail calls that a program can execute. However, a tail call erases any debug information about the calling function. Note that a tail call only happens with a particular syntax, where the return has one single function call as argument, and it is outside the scope of any to-be-closed variable. This syntax makes the calling function return exactly the returns of the called function, without any intervening action. So, none of the following examples are tail calls:
形式为 return *functioncall*
的调用不在要关闭的变量的范围内,称为尾调用。Lua 实现正确的尾调用(或正确的尾递归):在尾调用中,被调用的函数重用调用函数的栈条目。因此,程序可以执行的嵌套尾调用的数量没有限制。但是,尾调用会擦除有关调用函数的任何调试信息。请注意,尾调用仅发生在特定语法中,其中 return 只有一个函数调用作为参数,并且它不在任何要关闭的变量的范围内。此语法使调用函数准确返回被调用函数的返回值,没有任何中间操作。因此,以下示例都不是尾调用:
return (f(x)) -- results adjusted to 1
return 2 * f(x) -- result multiplied by 2
return x, f(x) -- additional results
f(x); return -- results discarded
return x or f(x) -- results adjusted to 1
3.4.11 – Function Definitions 3.4.11 – 函数定义
The syntax for function definition is
函数定义的语法是
functiondef ::= function funcbody
funcbody ::= ‘(’ [parlist] ‘)’ block end
The following syntactic sugar simplifies function definitions:
以下语法糖简化了函数定义:
stat ::= function funcname funcbody
stat ::= local function Name funcbody
funcname ::= Name {‘.’ Name} [‘:’ Name]
The statement 语句
function f () body end
translates to 翻译为
f = function () body end
The statement 语句
function t.a.b.c.f () body end
translates to 翻译为
t.a.b.c.f = function () body end
The statement 语句
local function f () body end
translates to 翻译为
local f; f = function () body end
not to 而不是
local f = function () body end
(This only makes a difference when the body of the function contains references to f
.)
(这仅在函数体包含对 f
的引用时才有所不同。)
A function definition is an executable expression, whose value has type function. When Lua precompiles a chunk, all its function bodies are precompiled too, but they are not created yet. Then, whenever Lua executes the function definition, the function is instantiated (or closed). This function instance, or closure, is the final value of the expression.
函数定义是一个可执行表达式,其值具有函数类型。当 Lua 预编译一个块时,其所有函数体也会被预编译,但它们尚未创建。然后,每当 Lua 执行函数定义时,该函数都会被实例化(或闭合)。此函数实例或闭包是表达式的最终值。
Parameters act as local variables that are initialized with the argument values:
参数充当用参数值初始化的局部变量:
parlist ::= namelist [‘,’ ‘...’] | ‘...’
When a Lua function is called, it adjusts its list of arguments to the length of its list of parameters (see §3.4.12), unless the function is a variadic function, which is indicated by three dots (’...
’) at the end of its parameter list. A variadic function does not adjust its argument list; instead, it collects all extra arguments and supplies them to the function through a vararg expression, which is also written as three dots. The value of this expression is a list of all actual extra arguments, similar to a function with multiple results (see §3.4.12).
当调用 Lua 函数时,它会调整其参数列表的长度以匹配其参数列表的长度(请参阅 §3.4.12),除非该函数是可变参数函数,这由其参数列表末尾的三个点(’ ...
‘)表示。可变参数函数不会调整其参数列表;相反,它会收集所有额外的参数,并通过 vararg 表达式将它们提供给函数,该表达式也写为三个点。此表达式的值是所有实际额外参数的列表,类似于具有多个结果的函数(请参阅 §3.4.12)。
As an example, consider the following definitions:
例如,考虑以下定义:
function f(a, b) end
function g(a, b, ...) end
function r() return 1,2,3 end
Then, we have the following mapping from arguments to parameters and to the vararg expression:
然后,我们有从参数到参数和到 vararg 表达式的以下映射:
CALL PARAMETERS
f(3) a=3, b=nil
f(3, 4) a=3, b=4
f(3, 4, 5) a=3, b=4
f(r(), 10) a=1, b=10
f(r()) a=1, b=2
g(3) a=3, b=nil, ... --> (nothing)
g(3, 4) a=3, b=4, ... --> (nothing)
g(3, 4, 5, 8) a=3, b=4, ... --> 5 8
g(5, r()) a=5, b=1, ... --> 2 3
Results are returned using the return statement (see §3.3.4). If control reaches the end of a function without encountering a return statement, then the function returns with no results.
结果使用 return 语句返回(参见 §3.3.4)。如果控制到达函数末尾而没有遇到 return 语句,则函数返回无结果。
There is a system-dependent limit on the number of values that a function may return. This limit is guaranteed to be greater than 1000.
对于函数可以返回的值的数量,存在一个与系统相关的限制。此限制保证大于 1000。
The colon syntax is used to emulate methods, adding an implicit extra parameter self
to the function. Thus, the statement
冒号语法用于模拟方法,向函数添加一个隐式额外参数 self
。因此,语句
function t.a.b.c:f (params) body end
is syntactic sugar for
是
t.a.b.c.f = function (self, params) body end
3.4.12 – Lists of expressions, multiple results, and adjustment 的语法糖 3.4.12 – 表达式列表、多个结果和调整
Both function calls and vararg expressions can result in multiple values. These expressions are called multires expressions.
函数调用和 vararg 表达式都可以产生多个值。这些表达式称为多结果表达式。
When a multires expression is used as the last element of a list of expressions, all results from the expression are added to the list of values produced by the list of expressions. Note that a single expression in a place that expects a list of expressions is the last expression in that (singleton) list.
当多结果表达式用作表达式列表的最后一个元素时,表达式中的所有结果都会添加到表达式列表生成的值列表中。请注意,在期望表达式列表的位置中的单个表达式是该(单例)列表中的最后一个表达式。
These are the places where Lua expects a list of expressions:
以下是 Lua 期望表达式列表的位置:
- A return statement, for instance
return e1, e2, e3
(see §3.3.4). 例如,一个 return 语句return e1, e2, e3
(参见 §3.3.4)。 - A table constructor, for instance
{e1, e2, e3}
(see §3.4.9). 一个表构造器,例如{e1, e2, e3}
(参见 §3.4.9)。 - The arguments of a function call, for instance
foo(e1, e2, e3)
(see §3.4.10). 一个函数调用的参数,例如foo(e1, e2, e3)
(参见 §3.4.10)。 - A multiple assignment, for instance
a , b, c = e1, e2, e3
(see §3.3.3). 一个多重赋值,例如a , b, c = e1, e2, e3
(参见 §3.3.3)。 - A local declaration, for instance
local a , b, c = e1, e2, e3
(see §3.3.7). 一个局部声明,例如local a , b, c = e1, e2, e3
(参见 §3.3.7)。 - The initial values in a generic for loop, for instance
for k in e1, e2, e3 do ... end
(see §3.3.5). 一个泛型 for 循环中的初始值,例如for k in e1, e2, e3 do ... end
(参见 §3.3.5)。
In the last four cases, the list of values from the list of expressions must be adjusted to a specific length: the number of parameters in a call to a non-variadic function (see §3.4.11), the number of variables in a multiple assignment or a local declaration, and exactly four values for a generic for loop. The adjustment follows these rules: If there are more values than needed, the extra values are thrown away; if there are fewer values than needed, the list is extended with nil’s. When the list of expressions ends with a multires expression, all results from that expression enter the list of values before the adjustment.
在最后四种情况下,来自表达式列表的值列表必须调整为特定长度:非变参函数调用中的参数数量(参见 §3.4.11)、多重赋值或局部声明中的变量数量,以及泛型 for 循环中的四个值。调整遵循以下规则:如果值多于需要的值,则丢弃多余的值;如果值少于需要的值,则用 nil 扩展列表。当表达式列表以多结果表达式结尾时,该表达式中的所有结果在调整之前进入值列表。
When a multires expression is used in a list of expressions without being the last element, or in a place where the syntax expects a single expression, Lua adjusts the result list of that expression to one element. As a particular case, the syntax expects a single expression inside a parenthesized expression; therefore, adding parentheses around a multires expression forces it to produce exactly one result.
当一个多结果表达式被用在一个表达式列表中且不是最后一个元素,或者在语法期望一个单一表达式的某个位置,Lua 会将该表达式的结果列表调整为一个元素。作为一种特殊情况,语法期望在括号表达式中有一个单一表达式;因此,在多结果表达式周围添加括号会强制它产生一个结果。
We seldom need to use a vararg expression in a place where the syntax expects a single expression. (Usually it is simpler to add a regular parameter before the variadic part and use that parameter.) When there is such a need, we recommend assigning the vararg expression to a single variable and using that variable in its place.
我们很少需要在语法期望一个单一表达式的某个位置使用一个可变参数表达式。(通常在可变参数部分之前添加一个常规参数并使用该参数会更简单。)当有这种需要时,我们建议将可变参数表达式赋值给一个单一变量,并在其位置使用该变量。
Here are some examples of uses of mutlres expressions. In all cases, when the construction needs “the n-th result” and there is no such result, it uses a nil.
这里有一些多结果表达式的用法示例。在所有情况下,当构造需要“第 n 个结果”且没有这样的结果时,它会使用 nil。
print(x, f()) -- prints x and all results from f().
print(x, (f())) -- prints x and the first result from f().
print(f(), x) -- prints the first result from f() and x.
print(1 + f()) -- prints 1 added to the first result from f().
local x = ... -- x gets the first vararg argument.
x,y = ... -- x gets the first vararg argument,
-- y gets the second vararg argument.
x,y,z = w, f() -- x gets w, y gets the first result from f(),
-- z gets the second result from f().
x,y,z = f() -- x gets the first result from f(),
-- y gets the second result from f(),
-- z gets the third result from f().
x,y,z = f(), g() -- x gets the first result from f(),
-- y gets the first result from g(),
-- z gets the second result from g().
x,y,z = (f()) -- x gets the first result from f(), y and z get nil.
return f() -- returns all results from f().
return x, ... -- returns x and all received vararg arguments.
return x,y,f() -- returns x, y, and all results from f().
{f()} -- creates a list with all results from f().
{...} -- creates a list with all vararg arguments.
{f(), 5} -- creates a list with the first result from f() and 5.
3.5 – Visibility Rules 可见性规则
Lua is a lexically scoped language. The scope of a local variable begins at the first statement after its declaration and lasts until the last non-void statement of the innermost block that includes the declaration. (Void statements are labels and empty statements.) Consider the following example:
Lua 是一种词法作用域语言。局部变量的作用域从其声明后的第一个语句开始,并持续到包含该声明的最内层块的最后一个非空语句。(空语句是标签和空语句。)考虑以下示例:
x = 10 -- global variable
do -- new block
local x = x -- new 'x', with value 10
print(x) --> 10
x = x+1
do -- another block
local x = x+1 -- another 'x'
print(x) --> 12
end
print(x) --> 11
end
print(x) --> 10 (the global one)
Notice that, in a declaration like local x = x
, the new x
being declared is not in scope yet, and so the second x
refers to the outside variable.
请注意,在类似 local x = x
的声明中,正在声明的新 x
尚未在作用域中,因此第二个 x
引用外部变量。
Because of the lexical scoping rules, local variables can be freely accessed by functions defined inside their scope. A local variable used by an inner function is called an upvalue (or external local variable, or simply external variable) inside the inner function.
由于词法作用域规则,内部函数可以自由访问其作用域内定义的局部变量。内部函数中使用的局部变量称为上值(或外部局部变量,或简单地称为外部变量)。
Notice that each execution of a local statement defines new local variables. Consider the following example:
请注意,每次执行局部语句都会定义新的局部变量。考虑以下示例:
a = {}
local x = 20
for i = 1, 10 do
local y = 0
a[i] = function () y = y + 1; return x + y end
end
The loop creates ten closures (that is, ten instances of the anonymous function). Each of these closures uses a different y
variable, while all of them share the same x
.
该循环创建了十个闭包(即十个匿名函数实例)。这些闭包中的每一个都使用不同的 y
变量,而它们都共享相同的 x
。