Luaref

Nvim 的 `:help` 页面,生成 使用 tree-sitter-vimdoc 解析器。


LUA 参考手册
版本 0.3.0 2022 年 8 月 7 日
Vimdoc 版本 (c) 2006 Luis Carvalho <lexcarvalho at gmail dot com>
改编自 "Lua: 5.1 reference manual" R. Ierusalimschy, L. H. de Figueiredo, W. Celes 版权所有 (c) 2006 Lua.org, PUC-Rio。
请参阅 lua-ref-doc 获取有关本手册的信息。请参阅 lua-ref-copyright 获取版权和许可信息。

1 概述 luaref-intro

Lua 是一种扩展编程语言,旨在支持通用过程式编程,并提供数据描述功能。它还为面向对象编程、函数式编程和数据驱动编程提供良好的支持。Lua 旨在用作任何需要脚本语言的程序的强大、轻量级脚本语言。Lua 以库的形式实现,用简洁的 C 语言(即 ANSI C 和 C++ 的通用子集)编写。
作为一种扩展语言,Lua 没有“主程序”的概念:它只在嵌入式宿主客户端中运行,称为嵌入式程序或简称宿主。此宿主程序可以调用函数来执行一段 Lua 代码,可以写入和读取 Lua 变量,并且可以注册由 Lua 代码调用的 C 函数。通过使用 C 函数,可以扩展 Lua 以应对各种不同的领域,从而创建共享语法框架的自定义编程语言。
Lua 是免费软件,像往常一样提供,不提供任何担保,如其许可证中所述。本手册中描述的实现可以在 Lua 的官方网站 www.lua.org 上找到。
像任何其他参考手册一样,本文档在某些地方很枯燥。有关 Lua 设计背后决策的讨论,请参见 lua-ref-bibliography 中的参考文献。有关 Lua 编程的详细介绍,请参见 Roberto 的著作《Programming in Lua》。
Lua 在葡萄牙语中意为“月亮”,读音为 LOO-ah。

2 语言 lua-language

本节描述 Lua 的词汇、语法和语义。换句话说,本节描述哪些标记有效、它们如何组合以及它们的组合含义。
语言结构将使用通常的扩展 BNF 符号进行解释,其中 `{` a `}` 表示 0 个或多个 `a`,`[` a `]` 表示可选的 `a`。

2.1 词汇约定 lua-lexical

lua-names lua-identifiers Lua 中的名称(也称为标识符)可以是任何字母、数字和下划线的字符串,但不能以数字开头。这与大多数语言中标识符的定义一致。(字母的定义取决于当前语言环境:当前语言环境认为是字母的任何字符都可以在标识符中使用。)标识符用于命名变量和表格字段。
以下关键字是保留关键字,不能用作名称
and       break     do        else      elseif
end       false     for       function  if
in        local     nil       not       or
repeat    return    then      true      until     while
Lua 是一种区分大小写的语言:`and` 是一个保留字,但 `And` 和 `AND` 是两个不同的有效名称。按照惯例,以下划线加大写字母开头的名称(例如 `_VERSION`)保留用于 Lua 使用的内部全局变量。
以下字符串表示其他标记
+     -     *     /     %     ^     #
==    ~=    <=    >=    <     >     =
(     )     {     }     [     ]
;     :     ,     .     ..    ...
lua-literal
文字字符串可以用匹配的单引号或双引号分隔,可以包含以下 C 风格的转义序列
\a 响铃
\b 退格
\f 换页
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\\ 反斜杠
\" 引号(双引号)
\' 撇号(单引号)
此外,反斜杠后跟一个真实的换行符将导致字符串中的换行符。字符串中的字符也可以使用转义序列 `\ddd` 指定其数值,其中 `ddd` 是最多三个十进制数字的序列。(请注意,如果数值转义后面紧跟着一个数字,则必须使用三个数字来表示它。)Lua 中的字符串可以包含任何 8 位值,包括嵌入的零,它们可以指定为 `\0`。
要在用双引号(单引号)括起来的文字字符串中放入双引号(单引号)、换行符、反斜杠或嵌入的零,您必须使用转义序列。任何其他字符都可以直接插入文字中。(某些控制字符可能会导致文件系统出现问题,但 Lua 对它们没有问题。)
文字字符串也可以使用用长括号括起来的长格式定义。我们将级别为 n 的起始长括号定义为起始方括号后跟 n 个等号,再后跟另一个起始方括号。因此,级别为 0 的起始长括号写为 `[[`,级别为 1 的起始长括号写为 `[=[`,依此类推。结束长括号的定义类似;例如,级别为 4 的结束长括号写为 `]====]`。长字符串以任何级别的起始长括号开头,以同一级别的第一个结束长括号结尾。此括号形式的文字可以跨越多行,不会解释任何转义序列,并且会忽略任何其他级别的长括号。它们可以包含任何内容,除了相应级别的结束括号。
为方便起见,当起始长括号紧跟换行符时,换行符不会包含在字符串中。例如,在使用 ASCII 的系统中(其中 `a` 的代码为 97,换行符的代码为 10,`1` 的代码为 49),以下五个文字表示同一个字符串
a = 'alo\n123"'
a = "alo\n123\""
a = '\97lo\10\04923"'
a = [[alo
123"]]
a = [==[
alo
123"]==]
lua-numconstant
数值常量可以用可选的小数部分和可选的小数指数写出。Lua 还接受整数十六进制常量,在它们前面加上 `0x`。以下是一些有效的数值常量示例
3     3.0     3.1416  314.16e-2   0.31416E1   0xff   0x56
lua-comment
注释以双连字符 (--) 开头,位于字符串之外的任何位置。如果 `--` 后面的文本不是起始长括号,则注释为短注释,一直持续到行尾。否则,它为长注释,一直持续到相应的结束长括号。长注释通常用于暂时禁用代码。

2.2 值和类型 lua-values

Lua 是一种动态类型语言。这意味着变量没有类型;只有值才有类型。语言中没有类型定义。所有值都带有自己的类型。
Lua 中的所有值都是一等公民。这意味着所有值都可以存储在变量中,作为参数传递给其他函数,并作为结果返回。
lua-types lua-nil lua-true lua-false lua-number lua-string Lua 中有八种基本类型:`nil`、`boolean`、`number`、`string`、`function`、`userdata`、`thread` 和 `table`。Nil 是 `nil` 值的类型,其主要属性是与任何其他值不同;它通常表示没有有用的值。Boolean 是 `false` 和 `true` 值的类型。`nil` 和 `false` 都使条件变为假;任何其他值都会使其变为真。Number 表示实数(双精度浮点数)。(构建使用其他内部表示形式表示数字的 Lua 解释器很容易,例如单精度浮点数或长整数;请参见文件 `luaconf.h`。)String 表示字符数组。Lua 是 8 位干净的:字符串可以包含任何 8 位字符,包括嵌入的零 ( `\0` )(请参见 lua-literal)。
Lua 可以调用(和操作)用 Lua 编写的函数和用 C 编写的函数(请参见 lua-function)。
lua-userdatatype
提供 `userdata` 类型是为了允许将任意 C 数据存储在 Lua 变量中。此类型对应于一块原始内存,在 Lua 中没有预定义的操作,除了赋值和身份测试。但是,通过使用元表,程序员可以为 userdata 值定义操作(请参见 lua-metatable)。userdata 值不能在 Lua 中创建或修改,只能通过 C API 创建或修改。这保证了宿主程序拥有的数据的完整性。
lua-thread
`thread` 类型表示独立的执行线程,用于实现协程(请参见 lua-coroutine)。不要将 Lua 线程与操作系统线程混淆。Lua 在所有系统上都支持协程,即使是在不支持线程的系统上。
lua-table
`table` 类型实现关联数组,即不仅可以用数字索引,还可以用任何值(除了 `nil`)索引的数组。表格可以是异构的;也就是说,它们可以包含所有类型的值(除了 `nil`)。表格是 Lua 中唯一的结构化数据机制;它们可以用来表示普通数组、符号表、集合、记录、图、树等。为了表示记录,Lua 使用字段名称作为索引。语言通过提供 `a.name` 作为 `a["name"]` 的语法糖来支持此表示。在 Lua 中,有很多方便的方法来创建表格(请参见 lua-tableconstructor)。
与索引一样,表格字段的值可以是任何类型(除了 `nil`)。特别地,因为函数是一等公民,所以表格字段可以包含函数。因此表格也可以携带方法(请参见 lua-function-define)。
表格、函数、线程和(完整的)userdata 值都是对象:变量实际上不包含这些值,只包含对它们的引用。赋值、参数传递和函数返回值始终操作对这些值的引用;这些操作不涉及任何类型的复制。
库函数 `type` 返回一个字符串,描述给定值的类型(请参见 lua-type())。

2.2.1 隐式转换 lua-coercion

Lua 在运行时提供字符串和数值之间的自动转换。任何应用于字符串的算术运算都会尝试将该字符串转换为数字,遵循通常的转换规则。反之,每当在需要字符串的地方使用数字时,数字都会以合理的格式转换为字符串。要完全控制数字如何转换为字符串,请使用字符串库中的 `format` 函数(请参见 string.format())。

2.3 变量 lua-variables

变量是存储值的位置。Lua 中有三种类型的变量:全局变量、局部变量和表格字段。
单个名称可以表示一个全局变量或一个局部变量(或函数的形式参数,它是局部变量的一种特定形式)
var ::= Name
名称表示标识符,如 lua-lexical 中所定义。
任何变量都被认为是全局变量,除非明确声明为局部变量(请参见 lua-local)。局部变量是词法范围的:局部变量可以被定义在其范围内的函数自由访问(请参见 lua-visibility)。
在第一次给变量赋值之前,它的值为 `nil`。
方括号用于索引表格
var ::= prefixexp [ exp ]
第一个表达式 (prefixexp) 应该得到一个表值; 第二个表达式 (exp) 标识该表内的一个特定条目。 用于标识要索引的表的表达式具有受限的语法; 有关详细信息,请参见 lua-expressions
语法 var.NAME 只是 var["NAME"] 的语法糖。
var ::= prefixexp . Name
所有全局变量都作为普通 Lua 表的字段存在,称为环境表或简称环境(参见 lua-environments)。 每个函数都拥有对环境的单独引用,因此该函数中所有全局变量都将引用此环境表。 创建函数时,它将继承创建它的函数的环境。 要获取 Lua 函数的环境表,请调用 getfenv(参见 lua_getfenv())。 要替换它,请调用 setfenv(参见 setfenv())。(您只能通过调试库(参见 lua-lib-debug)来操作 C 函数的环境)。
对全局变量 x 的访问等同于 _env.x,而这又等同于
gettable_event(_env, "x")
其中 _env 是运行函数的环境。(_env 变量未在 Lua 中定义。 我们在这里仅出于解释目的使用它)。
对全局变量和表字段访问的含义可以通过元表进行更改。 对索引变量 t[i] 的访问等同于调用 gettable_event(t,i)。(有关 gettable_event 函数的完整描述,请参见 lua-metatable。 此函数未在 Lua 中定义或可调用。 我们在这里仅出于解释目的使用它)。

2.4 语句 lua-statement

Lua 支持一组几乎传统的语句,类似于 Pascal 或 C 中的语句。 此集合包括赋值、控制结构、函数调用和变量声明。

2.4.1 代码块 lua-chunk

Lua 的执行单元称为代码块。 代码块只是一个语句序列,它们按顺序执行。 每个语句都可以选择性地后跟一个分号
chunk ::= {stat [ ; ]}
没有空语句,因此 ;; 不合法。
Lua 将代码块视为具有可变数量参数的匿名函数的主体(参见 lua-function-define)。 因此,代码块可以定义局部变量、接收参数和返回值。
代码块可以存储在文件或主机程序中的字符串中。 当执行代码块时,它首先被预编译成虚拟机的指令,然后由虚拟机的解释器执行编译后的代码。
代码块也可以预编译成二进制形式;有关详细信息,请参见程序 luac。 源代码和编译后的代码形式可以互换使用;Lua 会自动检测文件类型并相应地执行。

2.4.2 代码块 lua-block

代码块是一个语句列表;从语法上讲,代码块与代码块相同
block ::= chunk
lua-do lua-end 代码块可以显式地分隔以生成单个语句
stat ::= do block end
显式代码块有助于控制变量声明的范围。 显式代码块有时也用于在另一个代码块的中间添加 returnbreak 语句(参见 lua-control)。

2.4.3 赋值 lua-assign

Lua 允许多重赋值。 因此,赋值的语法在左侧定义一个变量列表,在右侧定义一个表达式列表。 两个列表中的元素由逗号分隔
stat ::= varlist1 = explist1
varlist1 ::= var { , var }
explist1 ::= exp { , exp }
表达式在 lua-expressions 中讨论。
在赋值之前,值列表会根据变量列表的长度进行调整。 如果值多于需要的值,则会丢弃多余的值。 如果值少于需要的值,则列表会用尽可能多的 nil 扩展。 如果表达式列表以函数调用结束,则该调用返回的所有值都会在调整之前进入值列表(除非调用被括号括起来;参见 lua-expressions)。
赋值语句首先计算所有表达式,然后才执行赋值。 因此代码
i = 3
i, a[i] = i+1, 20
a[3] 设置为 20,不会影响 a[4],因为 a[i] 中的 i 在被赋值为 4 之前就已经被计算(为 3)。 同样,这行代码
x, y = y, x
交换了 xy 的值。
对全局变量和表字段赋值的含义可以通过元表进行更改。 对索引变量 t[i] = val 的赋值等同于 settable_event(t,i,val)。(有关 settable_event 函数的完整描述,请参见 lua-metatable。 此函数未在 Lua 中定义或可调用。 我们在这里仅出于解释目的使用它)。
对全局变量 x = val 的赋值等同于赋值 _env.x = val,而这又等同于
settable_event(_env, "x", val)
其中 _env 是运行函数的环境。(_env 变量未在 Lua 中定义。 我们在这里仅出于解释目的使用它)。

2.4.4 控制结构 lua-control

lua-if lua-then lua-else lua-elseif lua-while lua-repeat lua-until 控制结构 ifwhilerepeat 具有通常的含义和熟悉的语法
stat ::=  while  exp do block end
stat ::=  repeat  block until exp
stat ::=  if  exp then block { elseif exp then block }
          [ else block ] end
Lua 还具有 for 语句,它有两种形式(参见 lua-for)。
控制结构的条件表达式可以返回任何值。 falsenil 都被视为假。 所有与 nilfalse 不同的值都被视为真(尤其是数字 0 和空字符串也被视为真)。
repeat-until 循环中,内部代码块不以 until 关键字结尾,而是在条件之后结束。 因此,条件可以引用循环代码块内声明的局部变量。
lua-return
return 语句用于从函数或代码块(它只是一个函数)返回返回值。 函数和代码块可以返回多个值,因此 return 语句的语法如下
stat ::= return [explist1]
lua-break
break 语句用于终止 whilerepeatfor 循环的执行,跳过循环后的下一条语句
stat ::= break
break 会结束最内层的循环。
returnbreak 语句只能作为代码块的最后一条语句编写。 如果必须在代码块中间returnbreak,则可以使用显式的内部代码块,如 do return enddo break end 中的习惯用法,因为现在 returnbreak 是其(内部)代码块中的最后一条语句。

2.4.5 For 语句 for lua-for

for 语句有两种形式:一种是数值型的,另一种是泛型的。
数值型 for 循环在控制变量遍历算术级数时重复一段代码。 它具有以下语法
stat ::=  for  Name = exp , exp [ , exp ] do block end
block 从第一个 exp 的值开始重复执行,直到它以第三个 exp 为步长超过第二个 exp。 更准确地说,类似于
for var = e1, e2, e3 do block end
for 语句等同于以下代码
do
  local  var, limit, step  = tonumber(e1), tonumber(e2), tonumber(e3)
  if not (  var  and  limit  and  step  ) then error() end
  while (  step  >0 and  var  <=  limit  )
          or (  step  <=0 and  var  >=  limit  ) do
     block
     var  =  var  +  step
  end
end
请注意以下几点
所有三个控制表达式只计算一次,在循环开始之前。 它们都必须得出数字。
varlimitstep 是不可见的变量。 这些名称仅用于解释目的。
如果第三个表达式(步长)缺失,则使用步长 1。
可以使用 break 退出 for 循环。
循环变量 var 对循环来说是局部的;您不能在 for 结束或被中断后使用它的值。 如果需要这个值,请在中断或退出循环之前将其赋值给另一个变量。
for-in
泛型 for 语句使用称为 迭代器 的函数进行操作。 在每次迭代中,都会调用迭代器函数以生成一个新值,当此新值为 nil 时停止。 泛型 for 循环具有以下语法
stat ::=  for  namelist in explist1 do block end
namelist ::= Name { , Name }
类似于
for var1, ..., varn in explist do block end
for 语句等同于以下代码
do
  local  f, s, var  =  explist
  while true do
      local  var1, ..., varn  =  f(s, var)
      var  =  var1
      if  var  == nil then break end
      block
  end
end
请注意以下几点
for 语句,explist 只计算一次。 其结果是一个迭代器函数、一个 state 和第一个迭代器变量的初始值。
fsvar 是不可见的变量。 这些名称仅用于解释目的。
可以使用 break 退出 for 循环。
循环变量 var1, ..., varn 对循环来说是局部的;您不能在 for 结束之后使用它们的值。 如果需要这些值,请在中断或退出循环之前将其赋值给其他变量。

2.4.6 函数调用作为语句 lua-funcstatement

为了允许可能的副作用,函数调用可以作为语句执行
stat ::= functioncall
在这种情况下,所有返回值都会被丢弃。 函数调用在 lua-function 中解释。

2.4.7 局部声明 lua-local

局部变量可以在代码块中的任何地方声明。 声明可以包括初始赋值
stat ::=  local  namelist [ = explist1 ]
namelist ::= Name { , Name }
如果有,初始赋值具有与多重赋值相同的语义(参见 lua-assign)。 否则,所有变量都用 nil 初始化。
代码块也是一个代码块(参见 lua-chunk),因此可以在代码块中声明局部变量,而无需任何显式代码块。 此类局部变量的作用域扩展到代码块的末尾。
局部变量的可见性规则在 lua-visibility 中解释。

2.5 表达式 lua-expressions

Lua 中的基本表达式如下
exp ::= prefixexp
exp ::=  nil  |  false  |  true
exp ::= Number
exp ::= String
exp ::= function
exp ::= tableconstructor
exp ::= ...
exp ::= exp binop exp
exp ::= unop exp
prefixexp ::= var | functioncall | ( exp )
数字和文字字符串在 lua-lexical 中解释;变量在 lua-variables 中解释;函数定义在 lua-function-define 中解释;函数调用在 lua-function 中解释;表构造函数在 lua-tableconstructor 中解释。 变参表达式(用三个点 (...) 表示)只能在变参函数内部使用;它们在 lua-function-define 中解释。
二元运算符包括算术运算符(参见 lua-arithmetic)、关系运算符(参见 lua-relational)、逻辑运算符(参见 lua-logicalop)和连接运算符(参见 lua-concat)。 一元运算符包括一元减号(参见 lua-arithmetic)、一元 not(参见 lua-logicalop)和一元长度运算符(参见 lua-length)。
函数调用和变参表达式都可能得出多个值。 如果表达式用作语句(参见 lua-funcstatement)(仅对函数调用有效),则其返回值列表将被调整为零个元素,从而丢弃所有返回值。 如果表达式用作表达式列表的最后一个(或唯一的)元素,则不会进行调整(除非调用被括号括起来)。 在所有其他上下文中,Lua 将结果列表调整为一个元素,丢弃除第一个值以外的所有值。
以下是一些示例
f()                -- adjusted to 0 results
g(f(), x)          -- f() is adjusted to 1 result
g(x, f())          -- g gets x plus all results from f()
a,b,c = f(), x     -- f() is adjusted to 1 result (c gets nil)
a,b = ...          -- a gets the first vararg parameter, b gets
                   -- the second (both a and b may get nil if there
                   -- is no corresponding vararg parameter)
a,b,c = x, f()     -- f() is adjusted to 2 results
a,b,c = f()        -- f() is adjusted to 3 results
return f()         -- returns all results from f()
return ...         -- returns all received vararg parameters
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 parameters
{f(), nil}         -- f() is adjusted to 1 result
用括号括起来的表达式始终只产生一个值。因此,(f(x,y,z)) 始终是一个单一值,即使 f 返回多个值。((f(x,y,z)) 的值为 f 返回的第一个值,如果 f 没有返回值,则为 nil。)

2.5.1 算术运算符 lua-arithmetic

Lua 支持常见的算术运算符:二元运算符 +(加法)、-(减法)、*(乘法)、/(除法)、%(取模)和 ^(求幂);以及一元运算符 -(取反)。如果操作数是数字,或者可以转换为数字的字符串(参见 lua-coercion),则所有运算具有通常的含义。求幂运算适用于任何指数。例如,x^(-0.5) 计算 x 的平方根的倒数。取模运算定义如下
a % b == a - math.floor(a/b)*b
也就是说,它是将商向负无穷方向取整的除法的余数。

2.5.2 关系运算符 lua-relational

Lua 中的关系运算符是
==    ~=    <     >     <=    >=
这些运算符始终产生 falsetrue
相等运算符 (==) 首先比较其操作数的类型。如果类型不同,则结果为 false。否则,比较操作数的值。数字和字符串以通常的方式比较。对象(表、userdata、线程和函数)通过引用进行比较:只有当两个对象是同一个对象时,它们才被认为相等。每次创建新对象(表、userdata 或函数)时,此新对象都与任何先前存在的对象不同。
可以使用 "eq" 元方法更改 Lua 比较表和 userdata 的方式(参见 lua-metatable)。
强制转换规则 lua-coercion 不适用于相等比较。因此,"0"==0 评估为 falset[0]t["0"] 表示表中的不同条目。
运算符 ~= 恰好是相等运算符 (==) 的否定。
顺序运算符的工作原理如下:如果两个参数都是数字,则将它们作为数字进行比较。否则,如果两个参数都是字符串,则根据当前区域设置比较它们的值。否则,Lua 会尝试调用 "lt" 或 "le" 元方法(参见 lua-metatable)。

2.5.3 逻辑运算符 lua-logicalop

Lua 中的逻辑运算符是
and    or    not
与控制结构(参见 lua-control)一样,所有逻辑运算符都将 falsenil 视为假,其他任何值都视为真。
lua-not lua-and lua-or 否定运算符 not 始终返回 falsetrue。合取运算符 and 返回其第一个参数,如果此值为 falsenil;否则,and 返回其第二个参数。析取运算符 or 返回其第一个参数,如果此值不同于 nilfalse;否则,or 返回其第二个参数。andor 都使用短路求值,也就是说,只有在必要时才求值第二个操作数。以下是一些示例
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
(在本手册中,--> 表示前面表达式的结果。)

2.5.4 连接 lua-concat

Lua 中的字符串连接运算符用两个点 (..) 表示。如果两个操作数都是字符串或数字,则根据 lua-coercion 中提到的规则将它们转换为字符串。否则,将调用 "concat" 元方法(参见 lua-metatable)。

2.5.5 长度运算符 lua-# lua-length

长度运算符用一元运算符 # 表示。字符串的长度是指其字节数(即,每个字符都是一个字节时字符串长度的通常含义)。
t 的长度被定义为任何整型索引 n,使得 t[n] 不为 nilt[n+1]nil;此外,如果 t[1]nil,则 n 可以为零。对于一个正规数组,其非 nil 值从 1 到给定的 n,其长度恰好是那个 n,即其最后一个值的索引。如果数组有 "空洞"(即,其他非 nil 值之间的 nil 值),则 #t 可以是直接位于 nil 值之前的任何索引(即,它可以将任何这样的 nil 值视为数组的结尾)。

2.5.6 优先级 lua-precedence

Lua 中的运算符优先级遵循下表,从低到高优先级
or
and
<     >     <=    >=    ~=    ==
..
+     -
*     /
not   #     - (unary)
^
像往常一样,可以使用括号来改变表达式中的优先级。连接运算符 (..) 和求幂运算符 (^) 是右结合的。所有其他二元运算符都是左结合的。

2.5.7 表构造器 lua-tableconstructor

表构造器是创建表的表达式。每次评估构造器时,都会创建一个新表。构造器可以用来创建空表,或者创建表并初始化其某些字段。构造器的通用语法是
tableconstructor ::= { [ fieldlist ] }
fieldlist ::= field { fieldsep field } [ fieldsep ]
field ::= [ exp ]  = exp | Name = exp | exp
fieldsep ::=  , |  ;
每个 [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 }
等效于
do
  local t = {}
  t[f(1)] = g
  t[1] = "x"         -- 1st exp
  t[2] = "y"         -- 2nd exp
  t.x = 1            -- temp["x"] = 1
  t[3] = f(x)        -- 3rd exp
  t[30] = 23
  t[4] = 45          -- 4th exp
  a = t
end
如果列表中的最后一个字段是 exp 形式,并且表达式是函数调用,则该调用返回的所有值将依次进入列表(参见 lua-function)。为了避免这种情况,请将函数调用括在括号中(参见 lua-expressions)。
字段列表可以有一个可选的尾部分隔符,方便机器生成的代码。

2.5.8 函数调用 lua-function

Lua 中的函数调用具有以下语法
functioncall ::= prefixexp args
在函数调用中,首先评估 prefixexpargs。如果 prefixexp 的值为 function 类型,则使用给定的参数调用此函数。否则,将调用 prefixexp 的 "call" 元方法,其第一个参数为 prefixexp 的值,之后是原始调用参数(参见 lua-metatable)。
形式
functioncall ::= prefixexp : Name args
可以用来调用 "方法"。调用 v:name( args )v.name(v, args ) 的语法糖,除了 v 只被评估一次。
参数具有以下语法
args ::=  ( [ explist1 ] )
args ::= tableconstructor
args ::= String
所有参数表达式都在调用之前进行评估。f{ fields } 形式的调用是 f({ fields }) 的语法糖,也就是说,参数列表是一个新的单一表。f' string ' 形式的调用(或 f" string "f[[ string ]])是 f(' string ') 的语法糖,也就是说,参数列表是一个单一的字面字符串。
作为 Lua 自由格式语法的例外,您不能在函数调用中的 ( 之前放置换行符。此限制避免了语言中的一些歧义。如果您编写
a = f
(g).x(a)
Lua 会将其视为一条语句,即 a = f(g).x(a)。因此,如果您想要两条语句,则必须在它们之间添加一个分号。如果您实际上想要调用 f,则必须删除 (g) 之前的换行符。
lua-tailcall
return functioncall 形式的调用称为尾调用。Lua 实现正确的尾调用(或正确的尾递归):在尾调用中,被调用函数会重用调用函数的堆栈条目。因此,程序可以执行的嵌套尾调用数量没有限制。但是,尾调用会擦除调用函数的任何调试信息。请注意,尾调用只会在特定语法下发生,其中 return 只有一个函数调用作为参数;这种语法使得调用函数准确地返回被调用函数的返回值。因此,以下示例都不是尾调用
return (f(x))        -- results adjusted to 1
return 2 * f(x)
return x, f(x)       -- additional results
f(x); return         -- results discarded
return x or f(x)     -- results adjusted to 1

2.5.9 函数定义 lua-function-define

函数定义的语法是
function ::= function funcbody
funcbody ::= ( [ parlist1 ] ) block end
以下语法糖简化了函数定义
stat ::= function funcname funcbody
stat ::= local function Name funcbody
funcname ::= Name { . Name } [ : Name ]
语句
function f () body end
转换为
f = function () body end
语句
function t.a.b.c.f () body end
转换为
t.a.b.c.f = function () body end
语句
local function f () body end
转换为
local f; f = function f () body end
而不是
local f = function f () body end
(这只有在函数体包含对 f 的引用时才会有所不同。)
lua-closure
函数定义是一个可执行表达式,其值为 function 类型。当 Lua 预编译一个代码块时,其所有函数体也会被预编译。然后,每当 Lua 执行函数定义时,都会实例化(或闭包)该函数。此函数实例(或闭包)是表达式的最终值。同一函数的不同实例可能引用不同的外部局部变量,并且可能具有不同的环境表。
参数充当用参数值初始化的局部变量
parlist1 ::= namelist [ , ... ] | ...
lua-vararg
当调用函数时,参数列表会调整为参数列表的长度,除非该函数是变参函数或 vararg 函数,这用其参数列表末尾的三个点 (...) 表示。vararg 函数不会调整其参数列表;相反,它会收集所有额外的参数,并将它们通过 vararg 表达式传递给函数,该表达式也用三个点表示。此表达式的值为所有实际额外参数的列表,类似于具有多个结果的函数。如果在另一个表达式中或在表达式列表的中间使用 vararg 表达式,则其返回值列表将调整为一个元素。如果该表达式用作表达式列表的最后一个元素,则不会进行调整(除非调用被括在括号中)。
例如,考虑以下定义
function f(a, b) end
function g(a, b, ...) end
function r() return 1,2,3 end
然后,我们有从参数到参数以及到 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
使用 return 语句返回结果(参见 lua-control)。如果控制到达函数末尾而没有遇到 return 语句,则该函数将不带任何结果返回。
lua-colonsyntax
冒号语法用于定义方法,即具有隐式额外参数 self 的函数。因此,语句
function t.a.b.c:f ( params ) body end
t.a.b.c:f = function ( self, params ) body end

2.6 可见性规则 lua-visibility

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)
请注意,在 local x = x 这样的声明中,新声明的 x 尚未处于作用域中,因此第二个 x 指的是外部变量。
lua-upvalue
由于词法作用域规则,在它们的范围内定义的函数可以自由访问局部变量。内部函数使用的局部变量在内部函数中被称为上值或外部局部变量。
请注意,每次执行局部语句都会定义新的局部变量。考虑以下示例
a = {}
local x = 20
for i=1,10 do
  local y = 0
  a[i] = function () y=y+1; return x+y end
end
循环创建了十个闭包(即十个匿名函数实例)。这些闭包中的每一个都使用一个不同的 y 变量,而它们都共享同一个 x

2.7 错误处理 lua-errors

由于 Lua 是一种嵌入式扩展语言,所有 Lua 操作都从主机程序中的 C 代码开始,该代码调用 Lua 库中的函数(参见 lua_pcall())。每当在 Lua 编译或执行过程中发生错误时,控制权将返回到 C,C 可以采取适当的措施(例如,打印错误消息)。
Lua 代码可以通过调用 error 函数(参见 error())显式地生成错误。如果你需要在 Lua 中捕获错误,可以使用 pcall 函数(参见 pcall())。
Lua 中的每个值都可能有一个元表。这个元表是一个普通的 Lua 表格,它定义了原始表格和用户数据的行为,在某些特殊操作下。你可以通过设置元表中的特定字段来更改对象的某些行为方面。例如,当一个非数值作为加法的操作数时,Lua 会检查其元表中 "__add" 字段中的函数。如果找到,Lua 会调用该函数来执行加法。
我们把元表中的键叫做事件,把值叫做元方法。在前面的示例中,事件是 "add",元方法是执行加法的函数。
你可以通过 getmetatable 函数(参见 getmetatable())查询任何值的元表。
你可以通过 setmetatable 函数(参见 setmetatable())替换表格的元表。你不能从 Lua 中更改其他类型的元表(除非使用调试库);你必须为此使用 C API。
表格和用户数据具有各自的元表(尽管多个表格和用户数据可以共享同一个表格作为它们的元表);所有其他类型的值每种类型共享一个元表。因此,所有数字有一个元表,所有字符串有一个元表,等等。
元表可以控制对象在算术运算、顺序比较、连接、长度运算和索引方面的行为。元表还可以定义一个函数,在垃圾回收用户数据时调用。对于这些操作中的每一个,Lua 都关联着一个特定的键,称为事件。当 Lua 对某个值执行这些操作之一时,它会检查这个值是否有一个具有相应事件的元表。如果有,与该键关联的值(元方法)将控制 Lua 如何执行该操作。
元表控制下面列出的操作。每个操作都由其对应的名称标识。每个操作的键是一个字符串,其名称以两个下划线 __ 为前缀;例如,操作 "add" 的键是字符串 "__add"。这些操作的语义最好由一个 Lua 函数来解释,该函数描述了解释器如何执行该操作。
这里在 Lua 中显示的代码仅供说明;实际行为是硬编码在解释器中的,并且比这个模拟更有效。这些描述中使用的所有函数(rawgettonumber 等)都在 lua-lib-core 中描述。特别是,要检索给定对象的元方法,我们使用表达式
metatable(obj)[event]
这应该被理解为
rawget(metatable(obj) or {}, event)
也就是说,对元方法的访问不会调用其他元方法,对没有元表的对象的访问不会失败(它只会导致 nil)。
"add": __add()
------ + 操作。
下面的 getbinhandler 函数定义了 Lua 如何为二元运算选择一个处理程序。首先,Lua 会尝试第一个操作数。如果它的类型没有为该操作定义处理程序,那么 Lua 会尝试第二个操作数。
function getbinhandler (op1, op2, event)
  return metatable(op1)[event] or metatable(op2)[event]
end
使用此函数,op1 + op2 的行为是
function add_event (op1, op2)
  local o1, o2 = tonumber(op1), tonumber(op2)
  if o1 and o2 then  -- both operands are numeric?
    return o1 + o2   -- `+` here is the primitive `add`
  else  -- at least one of the operands is not numeric
    local h = getbinhandler(op1, op2, "__add")
    if h then
      -- call the handler with both operands
      return h(op1, op2)
    else  -- no handler available: default behavior
      error(...)
    end
  end
end
"sub": __sub()
------ - 操作。行为类似于 "add" 操作。
"mul": __mul()
------ * 操作。行为类似于 "add" 操作。
"div": __div()
------ / 操作。行为类似于 "add" 操作。
"mod": __mod()
------ % 操作。行为类似于 "add" 操作,其中操作 o1 - floor(o1/o2)*o2 作为原始操作。
"pow": __pow()
------ ^(求幂)操作。行为类似于 "add" 操作,其中函数 pow(来自 C 数学库)作为原始操作。
"unm": __unm()
------ 一元 - 操作。
function unm_event (op)
  local o = tonumber(op)
  if o then  -- operand is numeric?
    return -o  -- `-` here is the primitive `unm`
  else  -- the operand is not numeric.
    -- Try to get a handler from the operand
    local h = metatable(op).__unm
    if h then
      -- call the handler with the operand
      return h(op)
    else  -- no handler available: default behavior
      error(...)
    end
  end
end
"concat": __concat()
--------- ..(连接)操作。
function concat_event (op1, op2)
  if (type(op1) == "string" or type(op1) == "number") and
     (type(op2) == "string" or type(op2) == "number") then
    return op1 .. op2  -- primitive string concatenation
  else
    local h = getbinhandler(op1, op2, "__concat")
    if h then
      return h(op1, op2)
    else
      error(...)
    end
  end
end
"len": __len()
------ # 操作。
function len_event (op)
  if type(op) == "string" then
    return strlen(op)         -- primitive string length
  elseif type(op) == "table" then
    return #op                -- primitive table length
  else
    local h = metatable(op).__len
    if h then
      -- call the handler with the operand
      return h(op)
    else  -- no handler available: default behavior
      error(...)
    end
  end
end
"eq": __eq()
----- == 操作。
getcomphandler 函数定义了 Lua 如何为比较运算符选择一个元方法。只有当两个要比较的对象具有相同的类型以及为所选操作相同的元方法时,才会选择一个元方法。
function getcomphandler (op1, op2, event)
  if type(op1) ~= type(op2) then return nil end
  local mm1 = metatable(op1)[event]
  local mm2 = metatable(op2)[event]
  if mm1 == mm2 then return mm1 else return nil end
end
"eq" 事件定义如下
function eq_event (op1, op2)
  if type(op1) ~= type(op2) then  -- different types?
    return false   -- different objects
  end
  if op1 == op2 then   -- primitive equal?
    return true   -- objects are equal
  end
  -- try metamethod
  local h = getcomphandler(op1, op2, "__eq")
  if h then
    return h(op1, op2)
  else
    return false
  end
end
a ~= b 等价于 not (a == b)
"lt": __lt()
----- < 操作。
function lt_event (op1, op2)
  if type(op1) == "number" and type(op2) == "number" then
    return op1 < op2   -- numeric comparison
  elseif type(op1) == "string" and type(op2) == "string" then
    return op1 < op2   -- lexicographic comparison
  else
    local h = getcomphandler(op1, op2, "__lt")
    if h then
      return h(op1, op2)
    else
      error(...);
    end
  end
end
a > b 等价于 b < a
"le": __le()
----- <= 操作。
function le_event (op1, op2)
  if type(op1) == "number" and type(op2) == "number" then
    return op1 <= op2   -- numeric comparison
  elseif type(op1) == "string" and type(op2) == "string" then
    return op1 <= op2   -- lexicographic comparison
  else
    local h = getcomphandler(op1, op2, "__le")
    if h then
      return h(op1, op2)
    else
      h = getcomphandler(op1, op2, "__lt")
      if h then
        return not h(op2, op1)
      else
        error(...);
      end
    end
  end
end
a >= b 等价于 b <= a。请注意,在没有 "le" 元方法的情况下,Lua 会尝试 "lt",假设 a <= b 等价于 not (b < a)
"index": __index()
-------- 索引访问 table[key]
function gettable_event (table, key)
  local h
  if type(table) == "table" then
    local v = rawget(table, key)
    if v ~= nil then return v end
    h = metatable(table).__index
    if h == nil then return nil end
  else
    h = metatable(table).__index
    if h == nil then
      error(...);
    end
  end
  if type(h) == "function" then
    return h(table, key)      -- call the handler
  else return h[key]          -- or repeat operation on it
end
"newindex": __newindex()
----------- 索引赋值 table[key] = value
function settable_event (table, key, value)
  local h
  if type(table) == "table" then
    local v = rawget(table, key)
    if v ~= nil then rawset(table, key, value); return end
    h = metatable(table).__newindex
    if h == nil then rawset(table, key, value); return end
  else
    h = metatable(table).__newindex
    if h == nil then
      error(...);
    end
  end
  if type(h) == "function" then
    return h(table, key,value)    -- call the handler
  else h[key] = value             -- or repeat operation on it
end
"call": __call()
------- 当 Lua 调用一个值时被调用。
function function_event (func, ...)
  if type(func) == "function" then
    return func(...)   -- primitive call
  else
    local h = metatable(func).__call
    if h then
      return h(func, ...)
    else
      error(...)
    end
  end
end

2.9 环境 lua-environments

除了元表之外,线程、函数和用户数据类型的对象还与它们关联另一个表格,称为它们的環境。与元表一样,环境是常规表格,多个对象可以共享同一个环境。
与用户数据关联的环境对 Lua 没有任何意义。这只是一个方便的功能,可以让程序员将一个表格与一个用户数据关联起来。
与线程关联的环境称为全局环境。它们用作线程的默认环境以及由线程创建的非嵌套函数(通过 loadfile()loadstring()load())的默认环境,并且可以直接被 C 代码访问(参见 lua-pseudoindex)。
与 C 函数关联的环境可以直接被 C 代码访问(参见 lua-pseudoindex)。它们用作由函数创建的其他 C 函数的默认环境。
与 Lua 函数关联的环境用于解析函数中对全局变量的所有访问(参见 lua-variables)。它们用作由函数创建的其他 Lua 函数的默认环境。
你可以通过调用 setfenv 来更改 Lua 函数或正在运行线程的环境。你可以通过调用 getfenv(参见 lua_getfenv())来获取 Lua 函数或正在运行线程的环境。要操作其他对象的環境(用户数据、C 函数、其他线程),你必须使用 C API。

2.10 垃圾回收 lua-gc

Lua 执行自动内存管理。这意味着你无需担心为新对象分配内存,也无需担心在不再需要这些对象时释放内存。Lua 通过不时运行垃圾回收器来自动管理内存,以收集所有已死对象(即不再从 Lua 可访问的这些对象)。Lua 中的所有对象都受自动管理:表格、用户数据、函数、线程和字符串。
Lua 实现了一个增量标记-清除收集器。它使用两个数字来控制其垃圾回收周期:垃圾回收器暂停和垃圾回收器步长乘数。
垃圾回收器暂停控制收集器在开始一个新的周期之前等待多长时间。较大的值使收集器不那么积极。小于 1 的值意味着收集器不会等待开始一个新的周期。值为 2 意味着收集器会等待使用中的总内存加倍,然后再开始一个新的周期。
步长乘数控制收集器相对于内存分配的速度。较大的值使收集器更积极,但也增加了每个增量步骤的大小。小于 1 的值使收集器太慢,可能会导致收集器永远无法完成一个周期。默认值 2 意味着收集器以内存分配的 "两倍" 速度运行。
你可以通过在 C 中调用 lua_gc(参见 lua_gc())或在 Lua 中调用 collectgarbage(参见 collectgarbage())来更改这些数字。两者都以百分比作为参数(因此参数 100 表示实际值为 1)。使用这些函数,你还可以直接控制收集器(例如,停止和重新启动它)。

2.10.1 垃圾回收元方法 lua-gc-meta

使用 C API,您可以为用户数据设置垃圾收集器元方法(参见 lua-metatable)。这些元方法也被称为终结器。终结器允许您协调 Lua 的垃圾收集与外部资源管理(例如关闭文件、网络或数据库连接,或释放您自己的内存)。
__gc
在它们的元表中具有 __gc 字段的垃圾用户数据不会立即被垃圾收集器收集。相反,Lua 会将它们放到一个列表中。在收集之后,Lua 会对该列表中的每个用户数据执行以下函数的等效操作
function gc_event (udata)
  local h = metatable(udata).__gc
  if h then
    h(udata)
  end
end
在每个垃圾收集周期结束时,用户数据的终结器会按照创建顺序的逆序调用,这些用户数据在该周期内被收集。也就是说,第一个被调用的终结器是与程序中最后创建的用户数据关联的终结器。

2.10.2 - 弱表 lua-weaktable

弱表是一个元素为弱引用的表。弱引用会被垃圾收集器忽略。换句话说,如果唯一指向某个对象的引用是弱引用,那么垃圾收集器将收集该对象。
__mode
弱表可以具有弱键、弱值或两者兼有。具有弱键的表允许收集其键,但阻止收集其值。具有弱键和弱值的表允许收集键和值。在任何情况下,如果键或值被收集,则整个键值对将从表中删除。表的弱属性由其元表的 __mode 字段的值控制。如果 __mode 字段是一个包含字符 k 的字符串,则表中的键是弱的。如果 __mode 包含 v,则表中的值是弱的。
在使用表作为元表之后,您不应该更改其 __mode 字段的值。否则,由该元表控制的表的弱行为将是未定义的。

2.11 协程 lua-coroutine

Lua 支持协程,也称为协作式多线程。Lua 中的协程代表一个独立的执行线程。然而,与多线程系统中的线程不同,协程只有通过显式调用 yield 函数才会挂起其执行。
您可以通过调用 coroutine.create 来创建一个协程(参见 coroutine.create())。它的唯一参数是一个函数,它是协程的主函数。create 函数只创建一个新的协程并返回指向它的句柄(一个 thread 类型的对象);它不会启动协程执行。
当您第一次调用 coroutine.resume(参见 coroutine.resume())时,将 coroutine.create 返回的线程作为其第一个参数传递,协程将开始其执行,从其主函数的第一行开始。传递给 coroutine.resume 的额外参数将传递给协程主函数。协程开始运行后,它会一直运行,直到它终止或 yield
协程可以通过两种方式终止其执行:正常终止,当其主函数返回时(显式或隐式,在最后一个指令之后);以及异常终止,如果存在不受保护的错误。在第一种情况下,coroutine.resume 返回 true,以及协程主函数返回的任何值。在发生错误的情况下,coroutine.resume 返回 false 和一个错误消息。
协程通过调用 coroutine.yield(参见 coroutine.yield())来挂起。当协程挂起时,相应的 coroutine.resume 会立即返回,即使挂起发生在嵌套函数调用中(也就是说,不是在主函数中,而是在直接或间接由主函数调用的函数中)。在挂起的情况下,coroutine.resume 也返回 true,以及传递给 coroutine.yield 的任何值。下次您恢复同一个协程时,它会从挂起的地方继续执行,coroutine.yield 的调用会返回传递给 coroutine.resume 的任何额外参数。
coroutine.create 一样,coroutine.wrap 函数(参见 coroutine.wrap())也创建了一个协程,但它不是返回协程本身,而是返回一个函数,当该函数被调用时,会恢复协程。传递给此函数的任何参数都会作为额外参数传递给 coroutine.resumecoroutine.wrap 返回 coroutine.resume 返回的所有值,除了第一个(布尔错误代码)。与 coroutine.resume 不同,coroutine.wrap 不捕获错误;任何错误都会传播给调用者。
例如,考虑下面的代码
function foo1 (a)
  print("foo", a)
  return coroutine.yield(2*a)
end
co = coroutine.create(function (a,b)
      print("co-body", a, b)
      local r = foo1(a+1)
      print("co-body", r)
      local r, s = coroutine.yield(a+b, a-b)
      print("co-body", r, s)
      return b, "end"
end)
print("main", coroutine.resume(co, 1, 10))
print("main", coroutine.resume(co, "r"))
print("main", coroutine.resume(co, "x", "y"))
print("main", coroutine.resume(co, "x", "y"))
当您运行它时,它会产生以下输出
co-body 1       10
foo     2
main    true    4
co-body r
main    true    11      -9
co-body x       y
main    true    10      end
main    false   cannot resume dead coroutine

3 应用编程接口 lua-API

本节描述了 Lua 的 C API,即主机程序可用于与 Lua 通信的 C 函数集。所有 API 函数和相关类型和常量都在头文件 lua.h 中声明。
即使我们使用“函数”这个词,API 中的任何功能都可以作为 提供。所有这些宏都使用每个参数恰好一次(除了第一个参数,它始终是 Lua 状态),因此不会产生隐藏的副作用。
与大多数 C 库一样,Lua API 函数不会检查其参数的有效性或一致性。但是,您可以通过在文件 luaconf.h 中为宏 luai_apicheck 编译 Lua 来更改此行为。

3.1 堆栈 lua-stack lua-apiStack

Lua 使用一个虚拟堆栈来传递值到 C 和从 C 传递值。此堆栈中的每个元素都代表一个 Lua 值(nil、数字、字符串等)。
每当 Lua 调用 C 时,被调用的函数都会获得一个新的堆栈,该堆栈独立于以前的堆栈以及仍处于活动状态的 C 函数的堆栈。此堆栈最初包含传递给 C 函数的任何参数,并且 C 函数将结果推送到此堆栈中,以便返回给调用者(参见 lua_CFunction)。
lua-stackindex
为了方便起见,API 中的大多数查询操作不遵循严格的堆栈纪律。相反,它们可以通过使用索引来引用堆栈中的任何元素:正索引表示一个绝对堆栈位置(从 1 开始);负索引表示从堆栈顶部的偏移量。更具体地说,如果堆栈有 n 个元素,那么索引 1 表示第一个元素(即,最先被推送到堆栈上的元素),索引 n 表示最后一个元素;索引 -1 也表示最后一个元素(即,位于顶部的元素),索引 -n 表示第一个元素。我们说一个索引是有效的,如果它在 1 到堆栈顶部之间(即,如果 1 <= abs(index) <= top)。

3.2 堆栈大小 lua-apiStackSize

当您与 Lua API 交互时,您有责任确保一致性。尤其是,您有责任控制堆栈溢出。您可以使用 lua_checkstack 函数来增加堆栈大小(参见 lua_checkstack())。
每当 Lua 调用 C 时,它都会确保至少有 LUA_MINSTACK 个堆栈位置可用。LUA_MINSTACK 定义为 20,因此通常您不必担心堆栈空间,除非您的代码有将元素推送到堆栈上的循环。
大多数查询函数接受作为索引的任何值,这些值位于可用的堆栈空间内,即,索引一直到您通过 lua_checkstack 设置的最大堆栈大小。这些索引称为可接受索引。更正式地说,我们将可接受索引定义如下
(index < 0 && abs(index) <= top) || (index > 0 && index <= stackspace)
请注意,0 从来不是可接受的索引。

3.3 伪索引 lua-pseudoindex

除非另有说明,否则接受有效索引的任何函数也可以使用伪索引调用,伪索引代表一些可供 C 代码访问的 Lua 值,但这些值不在堆栈中。伪索引用于访问线程环境、函数环境、注册表以及 C 函数的上值(参见 lua-cclosure)。
线程环境(全局变量所在的地方)始终位于伪索引 LUA_GLOBALSINDEX。运行的 C 函数的环境始终位于伪索引 LUA_ENVIRONINDEX
要访问和更改全局变量的值,您可以对环境表使用常规的表操作。例如,要访问全局变量的值,请执行以下操作
lua_getfield(L, LUA_GLOBALSINDEX, varname);

3.4 C 闭包 lua-cclosure

当创建一个 C 函数时,可以将一些值与之关联,从而创建一个 C 闭包;这些值被称为上值,并且在函数被调用时可以被函数访问(参见 lua_pushcclosure())。
每当一个 C 函数被调用时,它的上值都会位于特定的伪索引处。这些伪索引由宏 lua_upvalueindex 生成。与函数关联的第一个值位于位置 lua_upvalueindex(1),依此类推。对 lua_upvalueindex( n ) 的任何访问,其中 n 大于当前函数的上值数量,都会产生一个可接受的(但无效的)索引。

3.5 注册表 lua-registry

Lua 提供了一个注册表,它是一个预定义的表,任何 C 代码都可以使用它来存储它需要存储的任何 Lua 值。此表始终位于伪索引 LUA_REGISTRYINDEX。任何 C 库都可以将数据存储到此表中,但应注意选择与其他库使用的键不同的键,以避免冲突。通常,您应该使用一个包含您的库名称的字符串或一个带有 C 代码中 C 对象地址的轻量级用户数据作为键。
注册表中的整数键由辅助库实现的引用机制使用,因此不应用于其他目的。

3.6 C 中的错误处理 lua-apiError

在内部,Lua 使用 C longjmp 机制来处理错误。(如果您使用 C++,您也可以选择使用异常;参见文件 luaconf.h。)当 Lua 遇到任何错误(例如内存分配错误、类型错误、语法错误和运行时错误)时,它会引发错误;也就是说,它会进行长跳转。受保护的环境使用 setjmp 来设置恢复点;任何错误都会跳转到最近的活动恢复点。
API 中几乎任何函数都可能引发错误,例如,由于内存分配错误。以下函数在受保护模式下运行(也就是说,它们创建受保护的环境来运行),因此它们永远不会引发错误:lua_newstatelua_closelua_loadlua_pcalllua_cpcall(参见 lua_newstate()lua_close()lua_load()lua_pcall()lua_cpcall())。
在 C 函数内部,您可以通过调用 lua_error(参见 lua_error())来引发错误。

3.7 函数和类型 lua-apiFunctions

这里我们按字母顺序列出 C API 中的所有函数和类型。
lua_Alloc lua_Alloc
typedef void * (*lua_Alloc) (void *ud,
                             void *ptr,
                             size_t osize,
                             size_t nsize);
Lua 状态使用的内存分配函数的类型。分配器函数必须提供类似于realloc的功能,但并不完全相同。它的参数是ud,一个传递给lua_newstate的不透明指针(参见 lua_newstate());ptr,指向正在分配/重新分配/释放的块的指针;osize,块的原始大小;nsize,块的新大小。当ptrNULL时,当且仅当osize为零。当nsize为零时,分配器必须返回NULL;如果osize不为零,它应该释放ptr指向的块。当nsize不为零时,分配器当且仅当它无法满足请求时返回NULL。当nsize不为零且osize为零时,分配器应该像malloc一样工作。当nsizeosize不为零时,分配器像realloc一样工作。Lua 假设分配器在osize >= nsize时永远不会失败。
这是一个简单的分配器函数实现。它在辅助库中被luaL_newstate使用(参见 luaL_newstate())。
static void *l_alloc (void *ud, void *ptr, size_t osize,
                                           size_t nsize) {
  (void)ud;  (void)osize;  /* not used */
  if (nsize == 0) {
    free(ptr);
    return NULL;
  }
  else
    return realloc(ptr, nsize);
}
此代码假设free(NULL)没有效果,并且realloc(NULL, size)等同于malloc(size)。ANSI C 确保这两种行为。
lua_atpanic lua_atpanic()
lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
设置一个新的恐慌函数并返回旧的函数。
如果在任何受保护的环境之外发生错误,Lua 会调用一个panic function,然后调用exit(EXIT_FAILURE),从而退出主机应用程序。你的恐慌函数可以通过永不返回来避免此退出(例如,进行长跳转)。
恐慌函数可以在栈顶访问错误消息。
lua_call lua_call()
void lua_call (lua_State *L, int nargs, int nresults);
调用一个函数。
要调用一个函数,你必须使用以下协议:首先,将要调用的函数压入栈;然后,将函数的参数以直接顺序压入栈;也就是说,第一个参数先压入栈。最后,你调用lua_callnargs 是你压入栈的参数个数。当函数被调用时,所有参数和函数值都会从栈中弹出。函数结果在函数返回时压入栈。结果数将调整为nresults,除非nresultsLUA_MULTRET。在这种情况下,将压入函数的all结果。Lua 会确保返回的值适合栈空间。函数结果按直接顺序压入栈(第一个结果先压入栈),因此在调用之后,最后一个结果位于栈顶。
被调用函数内部的任何错误都会向上传播(使用longjmp)。
以下示例显示了主机程序如何执行与以下 Lua 代码等效的操作
a = f("how", t.x, 14)
以下是 C 代码
lua_getfield(L, LUA_GLOBALSINDEX, "f"); // function to be called
lua_pushstring(L, "how");                        // 1st argument
lua_getfield(L, LUA_GLOBALSINDEX, "t");   // table to be indexed
lua_getfield(L, -1, "x");        // push result of t.x (2nd arg)
lua_remove(L, -2);                  // remove 't' from the stack
lua_pushinteger(L, 14);                          // 3rd argument
lua_call(L, 3, 1);     // call 'f' with 3 arguments and 1 result
lua_setfield(L, LUA_GLOBALSINDEX, "a");        // set global 'a'
请注意,上面的代码是“平衡的”:在它结束时,栈回到了它的原始配置。这被认为是良好的编程实践。
lua_CFunction lua-cfunction lua_CFunction
typedef int (*lua_CFunction) (lua_State *L);
C 函数的类型。
为了与 Lua 正确通信,C 函数必须使用以下协议,它定义了参数和结果传递的方式:C 函数以直接顺序在其栈中接收来自 Lua 的参数(第一个参数先压入栈)。因此,当函数开始时,lua_gettop(L)(参见 lua_gettop())返回函数接收的参数个数。第一个参数(如果有)位于索引 1 处,最后一个参数位于索引 lua_gettop(L) 处。要将值返回给 Lua,C 函数只需将它们压入栈,以直接顺序(第一个结果先压入栈),并返回结果个数。栈中结果下方任何其他值都会被 Lua 正确丢弃。与 Lua 函数一样,由 Lua 调用的 C 函数也可以返回多个结果。
lua-cfunctionexample
例如,以下函数接收可变数量的数值参数并返回它们的平均值和总和
static int foo (lua_State *L) {
  int n = lua_gettop(L);    /* number of arguments */
  lua_Number sum = 0;
  int i;
  for (i = 1; i &lt;= n; i++) {
    if (!lua_isnumber(L, i)) {
      lua_pushstring(L, "incorrect argument");
      lua_error(L);
    }
    sum += lua_tonumber(L, i);
  }
  lua_pushnumber(L, sum/n); /* first result */
  lua_pushnumber(L, sum);   /* second result */
  return 2;                 /* number of results */
}
lua_checkstack lua_checkstack()
int lua_checkstack (lua_State *L, int extra);
确保栈中至少有extra个空闲栈槽。如果它无法将栈扩展到该大小,则返回 false。此函数从不缩小栈;如果栈已经大于新大小,则它保持不变。
lua_close lua_close()
void lua_close (lua_State *L);
销毁给定 Lua 状态中的所有对象(调用相应的垃圾收集元方法,如果有的话)并释放此状态使用的所有动态内存。在多个平台上,你可能不需要调用此函数,因为所有资源在主机程序结束时都会自然释放。另一方面,长时间运行的程序,例如守护进程或 Web 服务器,可能需要在不再需要时立即释放状态,以避免变得太大。
lua_concat lua_concat()
void lua_concat (lua_State *L, int n);
连接栈顶的n个值,弹出它们,并将结果留在栈顶。如果n为 1,则结果为栈上的单个字符串(即,函数不执行任何操作);如果n为 0,则结果为空字符串。连接操作遵循 Lua 的通常语义(参见 lua-concat)。
lua_cpcall lua_cpcall()
int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);
在受保护模式下调用 C 函数funcfunc在其栈中只包含一个元素,一个包含ud的轻量级用户数据。如果发生错误,lua_cpcall将返回与lua_pcall相同的错误代码(参见 lua_pcall()),以及栈顶的错误对象;否则,它返回零,并且不改变栈。func返回的所有值都会被丢弃。
lua_createtable lua_createtable()
void lua_createtable (lua_State *L, int narr, int nrec);
创建一个新的空表并将其压入栈。新表预先分配了narr个数组元素和nrec个非数组元素的空间。当你确切知道表将包含多少个元素时,这种预分配很有用。否则,你可以使用函数lua_newtable(参见 lua_newtable())。
lua_dump lua_dump()
int lua_dump (lua_State *L, lua_Writer writer, void *data);
将一个函数作为二进制块转储。接收栈顶的一个 Lua 函数,并生成一个二进制块,如果再次加载,它将生成一个等效于转储函数的函数。当它生成块的部分内容时,lua_dump会调用函数writer(参见 lua_Writer)并使用给定的data来写入它们。
返回的值是上次调用 writer 返回的错误代码;0 表示没有错误。
此函数不会从栈中弹出 Lua 函数。
lua_equal lua_equal()
int lua_equal (lua_State *L, int index1, int index2);
如果可接受索引index1index2处的两个值相等,则返回 1,遵循 Lua == 运算符的语义(即,可能调用元方法)。否则返回 0。如果任何索引无效,也返回 0。
lua_error lua_error()
int lua_error (lua_State *L);
生成一个 Lua 错误。错误消息(实际上可以是任何类型的 Lua 值)必须位于栈顶。此函数执行长跳转,因此永不返回(参见 luaL_error())。
lua_gc lua_gc()
int lua_gc (lua_State *L, int what, int data);
控制垃圾收集器。
此函数根据参数what的值执行多个任务
LUA_GCSTOP 停止垃圾收集器。
LUA_GCRESTART 重新启动垃圾收集器。
LUA_GCCOLLECT 执行一个完整的垃圾收集循环。
LUA_GCCOUNT 返回 Lua 当前使用的内存量(以 KB 为单位)。
LUA_GCCOUNTB 返回 Lua 当前使用的内存字节数除以 1024 后的余数。
LUA_GCSTEP 执行垃圾收集的增量步骤。步骤“大小”由data控制(较大的值意味着更多步骤),方式未指定。如果你想控制步骤大小,你必须通过实验调整data的值。如果步骤完成了一个垃圾收集循环,则函数返回 1。
LUA_GCSETPAUSEdata /100 设置为收集器的pause的新值(参见 lua-gc)。该函数返回 pause 的先前值。
LUA_GCSETSTEPMULdata /100 设置为收集器的step multiplier的新值(参见 lua-gc)。该函数返回 step multiplier 的先前值。
lua_getallocf lua_getallocf()
lua_Alloc lua_getallocf (lua_State *L, void **ud);
返回给定状态的内存分配函数。如果ud不为NULL,Lua 会将传递给lua_newstate的不透明指针存储在*ud中(参见 lua_newstate())。
lua_getfenv lua_getfenv()
void lua_getfenv (lua_State *L, int index);
将给定索引处值的 environment table 压入栈。
lua_getfield lua_getfield()
void lua_getfield (lua_State *L, int index, const char *k);
t[k]的值压入栈,其中t是给定有效索引index处的值。与 Lua 一样,此函数可能会触发“index”事件的元方法(参见 lua-metatable)。
lua_getglobal lua_getglobal()
void lua_getglobal (lua_State *L, const char *name);
将全局name的值压入栈。它被定义为宏
#define lua_getglobal(L,s)  lua_getfield(L, LUA_GLOBALSINDEX, s)
lua_getmetatable lua_getmetatable()
int lua_getmetatable (lua_State *L, int index);
将给定可接受索引处值的 metatable 压入栈。如果索引无效,或者值没有 metatable,则函数返回 0 并且不将任何内容压入栈。
lua_gettable lua_gettable()
void lua_gettable (lua_State *L, int index);
t[k]的值压入栈,其中t是给定有效索引index处的值,而k是栈顶的值。
此函数将键从栈中弹出(将结果值放在它的位置)。与 Lua 一样,此函数可能会触发“index”事件的元方法(参见 lua-metatable)。
lua_gettop lua_gettop()
int lua_gettop (lua_State *L);
返回栈中顶层元素的索引。因为索引从 1 开始,所以此结果等于栈中元素的个数(因此 0 表示空栈)。
lua_insert lua_insert()
void lua_insert (lua_State *L, int index);
将顶层元素移动到给定的有效索引,将此索引之上的元素向上移动以打开空间。不能使用伪索引调用,因为伪索引不是实际的栈位置。
lua_Integer lua_Integer
typedef ptrdiff_t lua_Integer;
Lua API 用于表示整数值的类型。
默认情况下,它是一个ptrdiff_t,通常是机器“舒适地”处理的最大整型。
lua_isboolean lua_isboolean()
int lua_isboolean (lua_State *L, int index);
如果给定可接受索引处的值的类型为布尔值,则返回 1,否则返回 0。
lua_iscfunction lua_iscfunction()
int lua_iscfunction (lua_State *L, int index);
如果给定可接受索引处的值为 C 函数,则返回 1,否则返回 0。
lua_isfunction lua_isfunction()
int lua_isfunction (lua_State *L, int index);
如果给定可接受索引处的值为函数(C 或 Lua),则返回 1,否则返回 0。
lua_islightuserdata lua_islightuserdata()
int lua_islightuserdata (lua_State *L, int index);
如果给定可接受索引处的值为轻量级用户数据,则返回 1,否则返回 0。
lua_isnil lua_isnil()
int lua_isnil (lua_State *L, int index);
如果给定可接受索引处的值为 nil,则返回 1,否则返回 0。
lua_isnumber lua_isnumber()
int lua_isnumber (lua_State *L, int index);
如果给定可接受索引处的值为数字或可转换为数字的字符串,则返回 1,否则返回 0。
lua_isstring lua_isstring()
int lua_isstring (lua_State *L, int index);
如果给定可接受索引处的值为字符串或数字(始终可转换为字符串),则返回 1,否则返回 0。
lua_istable lua_istable()
int lua_istable (lua_State *L, int index);
如果给定可接受索引处的值为表,则返回 1,否则返回 0。
lua_isthread lua_isthread()
int lua_isthread (lua_State *L, int index);
如果给定可接受索引处的值为线程,则返回 1,否则返回 0。
lua_isuserdata lua_isuserdata()
int lua_isuserdata (lua_State *L, int index);
如果给定可接受索引处的值为用户数据(完整或轻量级),则返回 1,否则返回 0。
lua_lessthan lua_lessthan()
int lua_lessthan (lua_State *L, int index1, int index2);
如果可接受索引 index1 处的值小于可接受索引 index2 处的值,则返回 1,遵循 Lua < 运算符的语义(即,可能会调用元方法)。否则返回 0。如果任何索引无效,也返回 0。
lua_load lua_load()
int lua_load (lua_State *L,
              lua_Reader reader,
              void *data,
              const char *chunkname);
加载 Lua 代码块。如果没有错误,lua_load 会将编译后的代码块作为 Lua 函数压入堆栈顶端。否则,它会压入一个错误消息。lua_load 的返回值为
0: 没有错误;
LUA_ERRSYNTAX: 预编译期间的语法错误;
LUA_ERRMEM: 内存分配错误。
此函数只加载代码块;它不会运行它。
lua_load 会自动检测代码块是文本还是二进制文件,并相应地加载它(参见程序 luac)。
lua_load 函数使用用户提供的 reader 函数来读取代码块(参见 lua_Reader)。data 参数是一个不透明的值,传递给读取器函数。
chunkname 参数为代码块提供一个名称,该名称用于错误消息和调试信息(参见 lua-apiDebug)。
lua_newstate lua_newstate()
lua_State *lua_newstate (lua_Alloc f, void *ud);
创建一个新的、独立的状态。如果无法创建状态(由于内存不足),则返回 NULL。参数 f 是分配器函数;Lua 通过此函数完成此状态的所有内存分配。第二个参数 ud 是一个不透明的指针,Lua 在每次调用分配器时都会简单地传递给它。
lua_newtable lua_newtable()
void lua_newtable (lua_State *L);
创建一个新的空表,并将其压入堆栈。它等效于 lua_createtable(L, 0, 0)(参见 lua_createtable())。
lua_newthread lua_newthread()
lua_State *lua_newthread (lua_State *L);
创建一个新线程,将其压入堆栈,并返回一个指向 lua_State(参见 lua_State)的指针,该指针表示此新线程。此函数返回的新状态与原始状态共享所有全局对象(例如表),但具有独立的执行堆栈。
没有明确的函数来关闭或销毁线程。线程与任何 Lua 对象一样,都受到垃圾回收的管理。
lua_newuserdata lua_newuserdata()
void *lua_newuserdata (lua_State *L, size_t size);
此函数使用给定的大小分配一个新的内存块,将一个新的完整用户数据(带有块地址)压入堆栈,并返回此地址。 userdata
用户数据表示 Lua 中的 C 值。完整用户数据表示一块内存。它是一个对象(像表):您必须创建它,它可以有自己的元表,并且您可以在它被收集时检测到它。完整用户数据只与自身相等(在原始相等下)。
当 Lua 收集具有 gc 元方法的完整用户数据时,Lua 会调用元方法并标记用户数据为已完成。当此用户数据再次被收集时,Lua 会释放其相应的内存。
lua_next lua_next()
int lua_next (lua_State *L, int index);
从堆栈中弹出键,并从给定索引处的表(在给定键之后“下一个”对)中压入键值对。如果表中没有更多元素,则 lua_next 返回 0(并且不压入任何内容)。
lua-tabletraversal
典型的遍历如下所示
/* table is in the stack at index 't' */
lua_pushnil(L);  /* first key */
while (lua_next(L, t) != 0) {
  /* uses 'key' (at index -2) and 'value' (at index -1) */
  printf("%s - %s\n",
         lua_typename(L, lua_type(L, -2)),
         lua_typename(L, lua_type(L, -1)));
  /* removes 'value'; keeps 'key' for next iteration */
  lua_pop(L, 1);
}
在遍历表时,不要直接对键调用 lua_tolstring(参见 lua_tolstring()),除非您知道键实际上是字符串。请记住,lua_tolstring更改给定索引处的值;这会混淆对 lua_next 的下一次调用。
lua_Number lua_Number
typedef double lua_Number;
Lua 中数字的类型。默认情况下,它是双精度浮点数,但可以在 luaconf.h 中更改。
通过配置文件,您可以更改 Lua 以使用其他类型来表示数字(例如,浮点数或长整数)。
lua_objlen lua_objlen()
size_t lua_objlen (lua_State *L, int index);
返回给定可接受索引处的值的“长度”:对于字符串,这是字符串长度;对于表,这是长度运算符(#)的结果;对于用户数据,这是为用户数据分配的内存块的大小;对于其他值,它是 0。
lua_pcall lua_pcall()
lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
在保护模式下调用函数。
nargsnresults 的含义与 lua_call 中相同(参见 lua_call())。如果调用期间没有错误,lua_pcall 的行为与 lua_call 完全相同。但是,如果发生任何错误,lua_pcall 会捕获它,在堆栈上压入一个值(错误消息),并返回一个错误代码。与 lua_call 一样,lua_pcall 始终从堆栈中删除函数及其参数。
如果 errfunc 为 0,则堆栈上返回的错误消息正是原始错误消息。否则,errfuncerror 处理程序函数 的堆栈索引。(在当前实现中,此索引不能是伪索引。)在运行时错误的情况下,此函数将使用错误消息被调用,其返回值将是 lua_pcall 在堆栈上返回的消息。
通常,错误处理程序函数用于向错误消息添加更多调试信息,例如堆栈回溯。在 lua_pcall 返回后,无法收集此类信息,因为到那时堆栈已经展开。
lua_pcall 函数在成功的情况下返回 0,或返回以下错误代码之一(在 lua.h 中定义)
LUA_ERRRUN 运行时错误。
LUA_ERRMEM 内存分配错误。对于此类错误,Lua 不会调用错误处理程序函数。
LUA_ERRERR 在运行错误处理程序函数时出错。
lua_pop lua_pop()
void lua_pop (lua_State *L, int n);
从堆栈中弹出 n 个元素。
lua_pushboolean lua_pushboolean()
void lua_pushboolean (lua_State *L, int b);
将值为 b 的布尔值压入堆栈。
lua_pushcclosure lua_pushcclosure()
void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
将一个新的 C 闭包压入堆栈。
当创建一个 C 函数时,可以为它关联一些值,从而创建一个 C 闭包(参见 lua-cclosure);这些值在每次调用该函数时都可以被访问。要将值与 C 函数关联,首先应将这些值压入堆栈(当有多个值时,第一个值先压入)。然后调用 lua_pushcclosure 来创建并压入 C 函数到堆栈中,参数 n 表示应与函数关联多少个值。lua_pushcclosure 还会从堆栈中弹出这些值。
lua_pushcfunction lua_pushcfunction()
void lua_pushcfunction (lua_State *L, lua_CFunction f);
将一个 C 函数压入堆栈。此函数接收一个指向 C 函数的指针,并将类型为 function 的 Lua 值压入堆栈,当调用该值时,会调用相应的 C 函数。
在 Lua 中注册的任何函数都必须遵循正确的协议来接收其参数并返回其结果(参见 lua_CFunction)。
lua_pushcfunction 被定义为一个宏
#define lua_pushcfunction(L,f)  lua_pushcclosure(L,f,0)
lua_pushfstring lua_pushfstring()
const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
将一个格式化的字符串压入堆栈,并返回指向此字符串的指针。它类似于 C 函数 sprintf,但有一些重要的区别
您不必为结果分配空间:结果是一个 Lua 字符串,Lua 会负责内存分配(以及通过垃圾回收进行的内存释放)。
转换说明符非常有限。没有标志、宽度或精度。转换说明符只能是 %%(在字符串中插入 %)、%s(插入一个以零结尾的字符串,没有大小限制)、%f(插入一个 lua_Number)、%p(将指针作为十六进制数插入)、%d(插入一个 int)和 %c(将 int 作为字符插入)。
lua_pushinteger lua_pushinteger()
void lua_pushinteger (lua_State *L, lua_Integer n);
将值为 n 的数字压入堆栈。
lua_pushlightuserdata lua_pushlightuserdata()
void lua_pushlightuserdata (lua_State *L, void *p);
将一个轻量级用户数据压入堆栈。 lua-lightuserdata
用户数据表示 Lua 中的 C 值。轻量级用户数据表示一个指针。它是一个值(像一个数字):您不会创建它,它没有单独的元表,并且不会被收集(因为它从未被创建)。轻量级用户数据与具有相同 C 地址的“任何”轻量级用户数据相等。
lua_pushlstring lua_pushlstring()
void lua_pushlstring (lua_State *L, const char *s, size_t len);
s 指向的字符串(大小为 len)压入堆栈。Lua 会对给定字符串进行(或重复使用)内部副本,因此在函数返回后可以立即释放或重复使用 s 处的内存。字符串可以包含嵌入的零。
lua_pushnil lua_pushnil()
void lua_pushnil (lua_State *L);
将一个 nil 值压入堆栈。
lua_pushnumber lua_pushnumber()
void lua_pushnumber (lua_State *L, lua_Number n);
将值为 n 的数字压入堆栈。
lua_pushstring lua_pushstring()
void lua_pushstring (lua_State *L, const char *s);
s 指向的以零结尾的字符串压入堆栈。Lua 会对给定字符串进行(或重复使用)内部副本,因此在函数返回后可以立即释放或重复使用 s 处的内存。字符串不能包含嵌入的零;假定它在第一个零处结束。
lua_pushthread lua_pushthread()
int lua_pushthread (lua_State *L);
L 表示的线程压入堆栈。如果此线程是其状态的主线程,则返回 1。
lua_pushvalue lua_pushvalue()
void lua_pushvalue (lua_State *L, int index);
将给定有效索引处的元素的副本推送到堆栈上。
lua_pushvfstring lua_pushvfstring()
const char *lua_pushvfstring (lua_State *L,
                              const char *fmt,
                              va_list argp);
等同于 lua_pushfstring(参见 lua_pushfstring()),区别在于它接收的是 va_list 而不是可变数量的参数。
lua_rawequal lua_rawequal()
int lua_rawequal (lua_State *L, int index1, int index2);
如果可接受索引 index1index2 中的两个值在原始上相等(即,不调用元方法),则返回 1。否则返回 0。如果任何索引无效,也返回 0。
lua_rawget lua_rawget()
void lua_rawget (lua_State *L, int index);
类似于 lua_gettable(参见 lua_gettable()),但执行的是原始访问(即,不使用元方法)。
lua_rawgeti lua_rawgeti()
void lua_rawgeti (lua_State *L, int index, int n);
t[n] 的值推送到堆栈上,其中 t 是给定有效索引 index 处的 value。访问是原始的;也就是说,它不调用元方法。
lua_rawset lua_rawset()
void lua_rawset (lua_State *L, int index);
类似于 lua_settable(参见 lua_settable()),但执行的是原始赋值(即,不使用元方法)。
lua_rawseti lua_rawseti()
void lua_rawseti (lua_State *L, int index, int n);
执行相当于 t[n] = v 的操作,其中 t 是给定有效索引 index 处的 value,而 v 是堆栈顶部的 value。
此函数将 value 从堆栈中弹出。赋值是原始的;也就是说,它不调用元方法。
lua_Reader lua_Reader
typedef const char * (*lua_Reader) (lua_State *L,
                                    void *data,
                                    size_t *size);
lua_load(参见 lua_load())使用的 reader 函数。每次需要 chunk 的另一部分时,lua_load 都会调用 reader,并将它的 data 参数传递过去。reader 必须返回指向包含 chunk 新部分的内存块的指针,并将 size 设置为块的大小。该块必须存在,直到再次调用 reader 函数。为了指示 chunk 的结束,reader 必须返回 NULL。reader 函数可以返回任何大小大于零的块。
lua_register lua_register()
void lua_register (lua_State *L,
                   const char *name,
                   lua_CFunction f);
将 C 函数 f 设置为全局 name 的新 value。它被定义为宏
#define lua_register(L,n,f) \
       (lua_pushcfunction(L, f), lua_setglobal(L, n))
lua_remove lua_remove()
void lua_remove (lua_State *L, int index);
移除给定有效索引处的元素,将该索引上方的元素向下移动以填补空缺。不能用伪索引调用,因为伪索引不是实际的堆栈位置。
lua_replace lua_replace()
void lua_replace (lua_State *L, int index);
将顶部的元素移动到给定位置(并将其弹出),而不移动任何元素(因此替换给定位置的 value)。
lua_resume lua_resume()
int lua_resume (lua_State *L, int narg);
在给定线程中启动和恢复协程。
要启动协程,您首先要创建一个新线程(参见 lua_newthread());然后,将主函数以及任何参数推送到它的堆栈上;然后调用 lua_resume(参见 lua_resume()),其中 narg 是参数的数量。此调用在协程挂起或完成执行时返回。当它返回时,堆栈包含传递给 lua_yield(参见 lua_yield())的所有 value,或主体函数返回的所有 value。lua_resume 如果协程挂起,则返回 LUA_YIELD;如果协程在没有错误的情况下完成执行,则返回 0;如果出现错误,则返回错误代码(参见 lua_pcall())。在发生错误的情况下,堆栈不会被展开,因此您可以使用调试 API 对其进行操作。错误消息位于堆栈的顶部。要重新启动协程,只需将作为 lua_yield 结果传递的 value 放入其堆栈中,然后调用 lua_resume
lua_setallocf lua_setallocf()
void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
将给定状态的分配器函数更改为 f,用户数据为 ud
lua_setfenv lua_setfenv()
int lua_setfenv (lua_State *L, int index);
从堆栈中弹出表格,并将其设置为给定索引处 value 的新环境。如果给定索引处的 value 既不是函数,也不是线程,也不是用户数据,lua_setfenv 返回 0。否则它返回 1。
lua_setfield lua_setfield()
void lua_setfield (lua_State *L, int index, const char *k);
执行相当于 t[k] = v 的操作,其中 t 是给定有效索引 index 处的 value,而 v 是堆栈顶部的 value。
此函数将 value 从堆栈中弹出。与 Lua 一样,此函数可能会触发“newindex”事件的元方法(参见 lua-metatable)。
lua_setglobal lua_setglobal()
void lua_setglobal (lua_State *L, const char *name);
从堆栈中弹出 value,并将其设置为全局 name 的新 value。它被定义为宏
#define lua_setglobal(L,s)   lua_setfield(L, LUA_GLOBALSINDEX, s)
lua_setmetatable lua_setmetatable()
int lua_setmetatable (lua_State *L, int index);
从堆栈中弹出表格,并将其设置为给定可接受索引处 value 的新元表格。
lua_settable lua_settable()
void lua_settable (lua_State *L, int index);
执行相当于 t[k] = v 的操作,其中 t 是给定有效索引 index 处的 value,v 是堆栈顶部的 value,而 k 是紧邻顶部的 value。
此函数将键和 value 都从堆栈中弹出。与 Lua 一样,此函数可能会触发“newindex”事件的元方法(参见 lua-metatable)。
lua_settop lua_settop()
void lua_settop (lua_State *L, int index);
接受任何可接受索引,或 0,并将堆栈顶部设置为此索引。如果新的顶部大于旧的顶部,则新的元素将填充 nil。如果 index 为 0,则所有堆栈元素都将被移除。
lua_State lua_State
typedef struct lua_State lua_State;
不透明结构,用于保存 Lua 解释器的所有状态。Lua 库是完全可重入的:它没有全局变量。有关状态的所有信息都保存在此结构中。
指向此状态的指针必须作为库中每个函数的第一个参数传递,除了 lua_newstate(参见 lua_newstate()),它从头开始创建 Lua 状态。
lua_status lua_status()
int lua_status (lua_State *L);
返回线程 L 的状态。
状态可以是正常线程的 0,线程完成执行时出现的错误代码,或线程挂起的 LUA_YIELD
lua_toboolean lua_toboolean()
int lua_toboolean (lua_State *L, int index);
将给定可接受索引处的 Lua value 转换为 C 布尔 value(0 或 1)。与 Lua 中的所有测试一样,lua_toboolean 对任何与 falsenil 不同的 Lua value 返回 1;否则它返回 0。它在使用非有效索引调用时也返回 0。(如果您只希望接受实际的布尔值,请使用 lua_isboolean lua_isboolean() 来测试 value 的类型。)
lua_tocfunction lua_tocfunction()
lua_CFunction lua_tocfunction (lua_State *L, int index);
将给定可接受索引处的 value 转换为 C 函数。该 value 必须是 C 函数;否则它返回 NULL
lua_tointeger lua_tointeger()
lua_Integer lua_tointeger (lua_State *L, int idx);
将给定可接受索引处的 Lua value 转换为带符号整型 lua_Integer(参见 lua_Integer)。Lua value 必须是数字或可以转换为数字的字符串(参见 lua-coercion);否则,lua_tointeger 返回 0。
如果数字不是整数,则它将以某种未指定的方式被截断。
lua_tolstring lua_tolstring()
const char *lua_tolstring (lua_State *L, int index, size_t *len);
将给定可接受索引处的 Lua value 转换为 C 字符串。如果 len 不为 NULL,它还会将 *len 设置为字符串长度。Lua value 必须是字符串或数字;否则,函数返回 NULL。如果 value 是数字,则 lua_tolstring更改堆栈中实际的 value 为 字符串。(当对遍历表格期间的键应用 lua_tolstring 时,此更改会使 lua_next lua_next() 变得混乱。)
lua_tolstring 返回指向 Lua 状态内字符串的完全对齐指针。此字符串在其最后一个字符之后始终包含一个零 (\0)(如 C 中一样),但其主体中可能包含其他零。由于 Lua 有垃圾回收,因此无法保证 lua_tolstring 返回的指针在相应的 value 从堆栈中移除后仍然有效。
lua_tonumber lua_tonumber()
lua_Number lua_tonumber (lua_State *L, int index);
将给定可接受索引处的 Lua value 转换为 C 类型 lua_Number(参见 lua_Number)。Lua value 必须是数字或可以转换为数字的字符串(参见 lua-coercion);否则,lua_tonumber 返回 0。
lua_topointer lua_topointer()
const void *lua_topointer (lua_State *L, int index);
将给定可接受索引处的 value 转换为通用 C 指针 (void*)。value 可以是用户数据、表格、线程或函数;否则,lua_topointer 返回 NULL。不同的对象将给出不同的指针。无法将指针转换回其原始 value。
通常此函数仅用于调试信息。
lua_tostring lua_tostring()
const char *lua_tostring (lua_State *L, int index);
等同于 lua_tolstring(参见 lua_tolstring()),其中 len 等于 NULL
lua_tothread lua_tothread()
lua_State *lua_tothread (lua_State *L, int index);
将给定可接受索引处的 value 转换为 Lua 线程(表示为 lua_State* lua_State)。此 value 必须是线程;否则,函数返回 NULL
lua_touserdata lua_touserdata()
void *lua_touserdata (lua_State *L, int index);
如果给定可接受索引处的 value 是完整用户数据,则返回其块地址。如果 value 是轻量级用户数据,则返回其指针。否则,它返回 NULL
lua_type lua_type()
int lua_type (lua_State *L, int index);
返回给定可接受索引处 value 的类型,或非有效索引的 LUA_TNONE(即,指向“空”堆栈位置的索引)。lua_type 返回的类型由 lua.h 中定义的以下常量编码:LUA_TNILLUA_TNUMBERLUA_TBOOLEANLUA_TSTRINGLUA_TTABLELUA_TFUNCTIONLUA_TUSERDATALUA_TTHREADLUA_TLIGHTUSERDATA
lua_typename lua_typename()
const char *lua_typename  (lua_State *L, int tp);
返回 tp 编码的类型的名称,tp 必须是 lua_type 返回的值之一。
lua_Writer lua_Writer
typedef int (*lua_Writer) (lua_State *L,
                           const void* p,
                           size_t sz,
                           void* ud);
lua_dump(参见 lua_dump())使用的 writer 函数。每次生成 chunk 的另一部分时,lua_dump 都会调用 writer,并将要写入的缓冲区 (p)、其大小 (sz) 以及传递给 lua_dumpdata 参数传递过去。
writer 返回错误代码:0 表示没有错误;任何其他 value 表示错误并阻止 lua_dump 再次调用 writer。
lua_xmove lua_xmove()
void lua_xmove (lua_State *from, lua_State *to, int n);
相同全局状态的不同线程之间交换值。
此函数从堆栈from中弹出n个值,并将它们推送到堆栈to上。
lua_yield lua_yield()
int lua_yield (lua_State *L, int nresults);
让出协程。
此函数只能作为 C 函数的返回值表达式调用,如下所示
return lua_yield (L, nresults);
当 C 函数以这种方式调用lua_yield时,正在运行的协程会暂停执行,并且调用启动此协程的lua_resume(参见 lua_resume())会返回。参数nresults是作为结果传递给lua_resume的堆栈中值的个数。
lua-stackexample
例如,如果堆栈从10 20 30 40 50*开始(从底部到顶部;*标记顶部),那么
lua_pushvalue(L, 3)    --> 10 20 30 40 50 30*
lua_pushvalue(L, -1)   --> 10 20 30 40 50 30 30*
lua_remove(L, -3)      --> 10 20 30 40 30 30*
lua_remove(L,  6)      --> 10 20 30 40 30*
lua_insert(L,  1)      --> 30 10 20 30 40*
lua_insert(L, -1)      --> 30 10 20 30 40*  (no effect)
lua_replace(L, 2)      --> 30 40 20 30*
lua_settop(L, -3)      --> 30 40*
lua_settop(L,  6)      --> 30 40 nil nil nil nil*

3.8 调试接口 lua-apiDebug

Lua 没有内置的调试功能。相反,它通过函数和钩子提供了一个特殊的接口。此接口允许构建各种调试器、分析器和其他需要解释器“内部信息”的工具。
lua_Debug lua_Debug
typedef struct lua_Debug {
    int event;
    const char *name;           /* (n) */
    const char *namewhat;       /* (n) */
    const char *what;           /* (S) */
    const char *source;         /* (S) */
    int currentline;            /* (l) */
    int nups;                   /* (u) number of upvalues */
    int linedefined;            /* (S) */
    int lastlinedefined;        /* (S) */
    char short_src[LUA_IDSIZE]; /* (S) */
    /* private part */
    other fields
} lua_Debug;
一个用于承载关于活动函数的不同信息的结构。lua_getstack(参见 lua_getstack())只填充此结构的私有部分,以便以后使用。要使用有用的信息填充lua_Debug的其他字段,请调用lua_getinfo(参见 lua_getinfo())。
lua_Debug的字段具有以下含义
source 如果函数是在字符串中定义的,那么source就是该字符串。如果函数是在文件中定义的,那么source@开头,后跟文件名。
short_src source的可“打印”版本,用于错误消息。
linedefined 函数定义开始的行号。
lastlinedefined 函数定义结束的行号。
what 如果函数是 Lua 函数,则为字符串"Lua";如果它是 C 函数,则为"C";如果它是块的主体部分,则为"main";如果它是进行了尾调用函数,则为"tail"。在后一种情况下,Lua 没有有关该函数的其他信息。
currentline 给定函数正在执行的当前行。当没有行信息可用时,currentline被设置为-1。
name 给定函数的合理名称。因为 Lua 中的函数是一等公民,所以它们没有固定的名称:一些函数可能是多个全局变量的值,而另一些函数可能只存储在表字段中。lua_getinfo函数检查函数是如何调用的,以找到一个合适的名称。如果它找不到名称,则name被设置为NULL
namewhat 解释name字段。namewhat的值可以是"global""local""method""field""upvalue"""(空字符串),具体取决于函数是如何调用的。(Lua 在没有其他选项适用时使用空字符串。)nups 函数的上值个数。
lua_gethook lua_gethook()
lua_Hook lua_gethook (lua_State *L);
返回当前的钩子函数。
lua_gethookcount lua_gethookcount()
int lua_gethookcount (lua_State *L);
返回当前的钩子计数。
lua_gethookmask lua_gethookmask()
int lua_gethookmask (lua_State *L);
返回当前的钩子掩码。
lua_getinfo lua_getinfo()
int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
返回关于特定函数或函数调用的信息。
要获取有关函数调用的信息,参数ar必须是有效的激活记录,该记录由先前对lua_getstack(参见 lua_getstack())的调用填充,或者作为钩子的参数给出(参见 lua_Hook)。
要获取关于函数的信息,您可以将它推送到堆栈上,并将what字符串的开头字符设置为>。(在这种情况下,lua_getinfo会弹出堆栈顶部的函数。)例如,要了解函数f是在哪一行定义的,您可以编写以下代码
lua_Debug ar;
lua_getfield(L, LUA_GLOBALSINDEX, "f");  /* get global 'f' */
lua_getinfo(L, ">S", &ar);
printf("%d\n", ar.linedefined);
what字符串中的每个字符都会选择要填充的ar结构中的某些字段或要推送到堆栈上的值
'n' 填充字段namenamewhat 'S' 填充字段sourceshort_srclinedefinedlastlinedefinedwhat 'l' 填充字段currentline 'u' 填充字段nups 'f' 将正在给定级别运行的函数推送到堆栈上 'L' 将一个表推送到堆栈上,该表的索引是函数中有效行的行号。(有效行是指与一些相关代码关联的行,即可以放置断点的行。非有效行包括空行和注释。)
此函数在出错时返回 0(例如,what中的选项无效)。
lua_getlocal lua_getlocal()
const char *lua_getlocal (lua_State *L, lua_Debug *ar, int n);
获取关于给定激活记录的局部变量的信息。参数ar必须是有效的激活记录,该记录由先前对lua_getstack(参见 lua_getstack())的调用填充,或者作为钩子的参数给出(参见 lua_Hook)。索引n选择要检查的局部变量(1 是第一个参数或活动的局部变量,依此类推,直到最后一个活动的局部变量)。lua_getlocal将变量的值推送到堆栈上并返回它的名称。
((左括号)开头的变量名称代表内部变量(循环控制变量、临时变量和 C 函数局部变量)。
当索引大于活动局部变量的个数时,返回NULL(并且不推送到堆栈上)。
lua_getstack lua_getstack()
int lua_getstack (lua_State *L, int level, lua_Debug *ar);
获取关于解释器运行时堆栈的信息。
此函数使用在给定级别执行的函数的激活记录的标识填充lua_Debug(参见 lua_Debug)结构的部分内容。级别 0 是当前正在运行的函数,而级别n+1是调用了级别n的函数。当没有错误时,lua_getstack返回 1;当使用大于堆栈深度的级别调用时,它返回 0。
lua_getupvalue lua_getupvalue()
const char *lua_getupvalue (lua_State *L, int funcindex, int n);
获取关于闭包上值的的信息。(对于 Lua 函数,上值是函数使用的外部局部变量,因此包含在其闭包中。)lua_getupvalue获取上值的索引n,将上值的值推送到堆栈上,并返回它的名称。funcindex指向堆栈中的闭包。(上值没有特定的顺序,因为它们在整个函数中都是活动的。因此,它们按任意顺序编号。)
当索引大于上值的个数时,返回NULL(并且不推送到堆栈上)。对于 C 函数,此函数使用空字符串""作为所有上值的名称。
lua_Hook lua_Hook
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
调试钩子函数的类型。
每当调用钩子时,它的ar参数的字段event都会设置为触发钩子的特定事件。Lua 使用以下常量来标识这些事件:LUA_HOOKCALLLUA_HOOKRETLUA_HOOKTAILRETLUA_HOOKLINELUA_HOOKCOUNT。此外,对于行事件,字段currentline也会被设置。要获取ar中任何其他字段的值,钩子必须调用lua_getinfo(参见 lua_getinfo())。对于返回事件,event可能是LUA_HOOKRET(正常值)或LUA_HOOKTAILRET。在后一种情况下,Lua 正在模拟从进行了尾调用的函数的返回;在这种情况下,调用lua_getinfo是无用的。
当 Lua 正在运行钩子时,它会禁用对钩子的其他调用。因此,如果钩子调用 Lua 来执行函数或块,则此执行会在不调用任何钩子的情况下发生。
lua_sethook lua_sethook()
int lua_sethook (lua_State *L, lua_Hook f, int mask, int count);
设置调试钩子函数。
参数f是钩子函数。mask指定在哪些事件上调用钩子:它是由常量LUA_MASKCALLLUA_MASKRETLUA_MASKLINELUA_MASKCOUNT的按位运算形成的。count参数只有在掩码包含LUA_MASKCOUNT时才有意义。对于每个事件,钩子的调用方式如下所示
调用钩子:在解释器调用函数时被调用。钩子在 Lua 进入新函数后立即被调用,在函数获取其参数之前。
返回钩子:在解释器从函数返回时被调用。钩子在 Lua 离开函数之前立即被调用。您无法访问函数要返回的值。
行钩子:在解释器即将开始执行新代码行或跳转回代码中(即使是跳转到同一行)时被调用。(此事件仅在 Lua 正在执行 Lua 函数时发生。)
计数钩子:在解释器每执行count条指令后被调用。(此事件仅在 Lua 正在执行 Lua 函数时发生。)
通过将mask设置为零来禁用钩子。
lua_setlocal lua_setlocal()
const char *lua_setlocal (lua_State *L, lua_Debug *ar, int n);
设置给定激活记录的局部变量的值。参数arnlua_getlocal(参见 lua_getlocal())中的一样。lua_setlocal将堆栈顶部的值分配给变量并返回它的名称。它还会从堆栈中弹出值。
当索引大于活动局部变量的个数时,返回NULL(并且不弹出任何内容)。
lua_setupvalue lua_setupvalue()
const char *lua_setupvalue (lua_State *L, int funcindex, int n);
设置闭包上值的的值。它将堆栈顶部的值分配给上值并返回它的名称。它还会从堆栈中弹出值。参数funcindexnlua_getupvalue(参见 lua_getupvalue())中的一样。
当索引大于上值的个数时,返回NULL(并且不弹出任何内容)。
lua-debugexample
例如,以下函数列出了堆栈给定级别上函数的所有局部变量和上值的名称
int listvars (lua_State *L, int level) {
  lua_Debug ar;
  int i;
  const char *name;
  if (lua_getstack(L, level, &ar) == 0)
    return 0;  /* failure: no such level in the stack */
  i = 1;
  while ((name = lua_getlocal(L, &ar, i++)) != NULL) {
    printf("local %d %s\n", i-1, name);
    lua_pop(L, 1);  /* remove variable value */
  }
  lua_getinfo(L, "f", &ar);  /* retrieves function */
  i = 1;
  while ((name = lua_getupvalue(L, -1, i++)) != NULL) {
    printf("upvalue %d %s\n", i-1, name);
    lua_pop(L, 1);  /* remove upvalue value */
  }
  return 1;
}

4 辅助库 lua-aux

辅助库提供了几个方便的函数来连接 C 与 Lua。虽然基本 API 提供了 C 和 Lua 之间所有交互的基本函数,但辅助库为一些常见任务提供了更高级别的函数。
辅助库中的所有函数都在头文件lauxlib.h中定义,并且具有前缀luaL_
辅助库中的所有函数都是基于基本 API 构建的,因此它们没有提供无法使用该 API 完成的功能。
辅助库中的几个函数用于检查 C 函数参数。它们的名称始终为 luaL_check*luaL_opt*。如果检查不满足,所有这些函数都会引发错误。由于错误消息是针对参数格式化的(例如,“错误参数 #1”),因此不应将这些函数用于其他堆栈值。

4.1 函数和类型 lua-auxFunctions

这里我们按字母顺序列出辅助库中的所有函数和类型。
luaL_addchar luaL_addchar()
void luaL_addchar (luaL_Buffer *B, char c);
将字符 c 添加到缓冲区 B(参见 luaL_Buffer)。
luaL_addlstring luaL_addlstring()
void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);
s 指向的字符串(长度为 l)添加到缓冲区 B(参见 luaL_Buffer)。该字符串可能包含嵌入的零。
luaL_addsize luaL_addsize()
void luaL_addsize (luaL_Buffer *B, size_t n);
将先前复制到缓冲区区域(参见 luaL_prepbuffer())的长度为 n 的字符串添加到缓冲区 B(参见 luaL_Buffer)。
luaL_addstring luaL_addstring()
void luaL_addstring (luaL_Buffer *B, const char *s);
s 指向的以零结尾的字符串添加到缓冲区 B(参见 luaL_Buffer)。该字符串可能不包含嵌入的零。
luaL_addvalue luaL_addvalue()
void luaL_addvalue (luaL_Buffer *B);
将堆栈顶部的值添加到缓冲区 B(参见 luaL_Buffer)。弹出该值。
这是唯一可以在(并且必须)使用堆栈上的额外元素调用的字符串缓冲区函数,该元素是要添加到缓冲区的值。
luaL_argcheck luaL_argcheck()
void luaL_argcheck (lua_State *L,
                    int cond,
                    int narg,
                    const char *extramsg);
检查 cond 是否为真。如果不是,则使用以下消息引发错误,其中 func 从调用堆栈中检索
bad argument #<narg> to <func> (<extramsg>)
luaL_argerror luaL_argerror()
int luaL_argerror (lua_State *L, int narg, const char *extramsg);
使用以下消息引发错误,其中 func 从调用堆栈中检索
bad argument #<narg> to <func> (<extramsg>)
此函数永远不会返回,但使用它在 C 函数中作为 return luaL_argerror( args ) 是一个惯例。
luaL_Buffer luaL_Buffer
typedef struct luaL_Buffer luaL_Buffer;
字符串缓冲区 的类型。
字符串缓冲区允许 C 代码分段构建 Lua 字符串。它的使用模式如下
首先声明一个类型为 luaL_Buffer 的变量 b
然后使用调用 luaL_buffinit(L, &b) 初始化它(参见 luaL_buffinit())。
然后调用任何 luaL_add* 函数将字符串片段添加到缓冲区。
最后调用 luaL_pushresult(&b)(参见 luaL_pushresult())。此调用将最终字符串留在堆栈顶部。
在正常操作期间,字符串缓冲区使用可变数量的堆栈槽位。因此,在使用缓冲区时,不能假设知道堆栈的顶部位置。您可以在连续的缓冲区操作调用之间使用堆栈,只要该使用是平衡的;也就是说,当您调用缓冲区操作时,堆栈处于与前一个缓冲区操作后的立即状态相同的级别。(该规则的唯一例外是 luaL_addvalue luaL_addvalue()。)在调用 luaL_pushresult 后,堆栈将返回到初始化缓冲区时的级别,加上其顶部的最终字符串。
luaL_buffinit luaL_buffinit()
void luaL_buffinit (lua_State *L, luaL_Buffer *B);
初始化缓冲区 B。此函数不会分配任何空间;缓冲区必须声明为变量(参见 luaL_Buffer)。
luaL_callmeta luaL_callmeta()
int luaL_callmeta (lua_State *L, int obj, const char *e);
调用元方法。
如果索引 obj 处的对象具有元表,并且此元表具有字段 e,则此函数将调用此字段并将对象作为其唯一参数传递。在这种情况下,此函数返回 1 并将调用返回的值推送到堆栈中。如果没有元表或没有元方法,则此函数返回 0(不将任何值推送到堆栈中)。
luaL_checkany luaL_checkany()
void luaL_checkany (lua_State *L, int narg);
检查函数是否在位置 narg 处具有任何类型的参数(包括 nil)。
luaL_checkint luaL_checkint()
int luaL_checkint (lua_State *L, int narg);
检查函数参数 narg 是否为数字,并返回此数字转换为 int
luaL_checkinteger luaL_checkinteger()
lua_Integer luaL_checkinteger (lua_State *L, int narg);
检查函数参数 narg 是否为数字,并返回此数字转换为 lua_Integer(参见 lua_Integer)。
luaL_checklong luaL_checklong()
long luaL_checklong (lua_State *L, int narg);
检查函数参数 narg 是否为数字,并返回此数字转换为 long
luaL_checklstring luaL_checklstring()
const char *luaL_checklstring (lua_State *L, int narg, size_t *l);
检查函数参数 narg 是否为字符串并返回此字符串;如果 l 不为 NULL,则将 *l 填充为字符串的长度。
luaL_checknumber luaL_checknumber()
lua_Number luaL_checknumber (lua_State *L, int narg);
检查函数参数 narg 是否为数字,并返回此数字(参见 lua_Number)。
luaL_checkoption luaL_checkoption()
int luaL_checkoption (lua_State *L,
                      int narg,
                      const char *def,
                      const char *const lst[]);
检查函数参数 narg 是否为字符串,并在数组 lst(必须以 NULL 结尾)中搜索此字符串。返回数组中找到字符串的索引。如果参数不是字符串或无法找到字符串,则引发错误。
如果 def 不为 NULL,则当没有参数 narg 或此参数为 nil 时,该函数使用 def 作为默认值。
这是一个将字符串映射到 C 枚举的有用函数。(Lua 库中的常用约定是使用字符串而不是数字来选择选项。)
luaL_checkstack luaL_checkstack()
void luaL_checkstack (lua_State *L, int sz, const char *msg);
将堆栈大小增加到 top + sz 个元素,如果堆栈无法扩展到该大小,则引发错误。msg 是添加到错误消息中的附加文本。
luaL_checkstring luaL_checkstring()
const char *luaL_checkstring (lua_State *L, int narg);
检查函数参数 narg 是否为字符串并返回此字符串。
luaL_checktype luaL_checktype()
void luaL_checktype (lua_State *L, int narg, int t);
检查函数参数 narg 是否具有类型 t(参见 lua_type())。
luaL_checkudata luaL_checkudata()
void *luaL_checkudata (lua_State *L, int narg, const char *tname);
检查函数参数 narg 是否为类型 tname 的用户数据(参见 luaL_newmetatable())。
luaL_dofile luaL_dofile()
int luaL_dofile (lua_State *L, const char *filename);
加载并运行给定文件。它被定义为以下宏
(luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))
如果没有任何错误,则返回 0;如果发生错误,则返回 1。
luaL_dostring luaL_dostring()
int luaL_dostring (lua_State *L, const char *str);
加载并运行给定字符串。它被定义为以下宏
(luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))
如果没有任何错误,则返回 0;如果发生错误,则返回 1。
luaL_error luaL_error()
int luaL_error (lua_State *L, const char *fmt, ...);
引发错误。错误消息格式由 fmt 加上任何额外的参数给出,遵循 lua_pushfstring 的相同规则(参见 lua_pushfstring())。它还在消息开头添加了发生错误的文件名和行号,如果此信息可用。
此函数永远不会返回,但使用它在 C 函数中作为 return luaL_error( args ) 是一个惯例。
luaL_getmetafield luaL_getmetafield()
int luaL_getmetafield (lua_State *L, int obj, const char *e);
将索引 obj 处的对象元表中的字段 e 推送到堆栈中。如果对象没有元表,或者元表没有此字段,则返回 0 且不推入任何内容。
luaL_getmetatable luaL_getmetatable()
void luaL_getmetatable (lua_State *L, const char *tname);
将与注册表中名称 tname 关联的元表推送到堆栈中(参见 luaL_newmetatable())。
luaL_gsub luaL_gsub()
const char *luaL_gsub (lua_State *L,
                       const char *s,
                       const char *p,
                       const char *r);
通过将字符串 p 的任何出现替换为字符串 r 来创建字符串 s 的副本。将生成的字符串推送到堆栈并返回它。
luaL_loadbuffer luaL_loadbuffer()
int luaL_loadbuffer (lua_State *L,
                     const char *buff,
                     size_t sz,
                     const char *name);
将缓冲区加载为 Lua 代码块。此函数使用 lua_load(参见 lua_load())在 buff 指向的缓冲区中加载大小为 sz 的代码块。
此函数返回与 lua_load 相同的结果。name 是代码块名称,用于调试信息和错误消息。
luaL_loadfile luaL_loadfile()
int luaL_loadfile (lua_State *L, const char *filename);
将文件加载为 Lua 代码块。此函数使用 lua_load(参见 lua_load())加载名为 filename 的文件中的代码块。如果 filenameNULL,则从标准输入加载。如果文件的第一行以 # 开头,则忽略该行。
此函数返回与 lua_load 相同的结果,但如果无法打开/读取文件,则具有额外的错误代码 LUA_ERRFILE
lua_load 一样,此函数仅加载代码块;它不运行它。
luaL_loadstring luaL_loadstring()
int luaL_loadstring (lua_State *L, const char *s);
将字符串加载为 Lua 代码块。此函数使用 lua_load(参见 lua_load())在以零结尾的字符串 s 中加载代码块。
此函数返回与 lua_load 相同的结果。
lua_load 一样,此函数仅加载代码块;它不运行它。
luaL_newmetatable luaL_newmetatable()
int luaL_newmetatable (lua_State *L, const char *tname);
如果注册表已经具有键 tname,则返回 0。否则,创建一个新表用作用户数据的元表,将其添加到注册表中,键为 tname,并返回 1。
在这两种情况下,都将最终与注册表中的 tname 关联的值推送到堆栈中。
luaL_newstate luaL_newstate()
lua_State *luaL_newstate (void);
创建一个新的 Lua 状态。它调用 `lua_newstate`(参见 lua_newstate()),使用基于标准 C `realloc` 函数的分配器,然后设置一个 panic 函数(参见 lua_atpanic()),该函数在发生致命错误时将错误消息打印到标准错误输出。
返回新状态,如果存在内存分配错误,则返回 `NULL`。
luaL_openlibs luaL_openlibs()
void luaL_openlibs (lua_State *L);
将所有标准 Lua 库打开到给定状态。有关如何打开单个库的详细信息,请参见 lua-openlibs
luaL_optint luaL_optint()
int luaL_optint (lua_State *L, int narg, int d);
如果函数参数 `narg` 是一个数字,则返回此数字转换为 `int`。如果此参数缺失或为 `nil`,则返回 `d`。否则,将引发错误。
luaL_optinteger luaL_optinteger()
lua_Integer luaL_optinteger (lua_State *L,
                             int narg,
                             lua_Integer d);
如果函数参数 `narg` 是一个数字,则返回此数字转换为 `lua_Integer`(参见 lua_Integer)。如果此参数缺失或为 `nil`,则返回 `d`。否则,将引发错误。
luaL_optlong luaL_optlong()
long luaL_optlong (lua_State *L, int narg, long d);
如果函数参数 `narg` 是一个数字,则返回此数字转换为 `long`。如果此参数缺失或为 `nil`,则返回 `d`。否则,将引发错误。
luaL_optlstring luaL_optlstring()
const char *luaL_optlstring (lua_State *L,
                             int narg,
                             const char *d,
                             size_t *l);
如果函数参数 `narg` 是一个字符串,则返回此字符串。如果此参数缺失或为 `nil`,则返回 `d`。否则,将引发错误。
如果 `l` 不为 `NULL`,则将结果的长度填充到位置 `*l` 中。
luaL_optnumber luaL_optnumber()
lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number d);
如果函数参数 `narg` 是一个数字,则返回此数字。如果此参数缺失或为 `nil`,则返回 `d`。否则,将引发错误。
luaL_optstring luaL_optstring()
const char *luaL_optstring (lua_State *L,
                            int narg,
                            const char *d);
如果函数参数 `narg` 是一个字符串,则返回此字符串。如果此参数缺失或为 `nil`,则返回 `d`。否则,将引发错误。
luaL_prepbuffer luaL_prepbuffer()
char *luaL_prepbuffer (luaL_Buffer *B);
返回一个指向大小为 `LUAL_BUFFERSIZE` 的空间的地址,您可以在其中复制一个字符串以添加到缓冲区 `B` 中(参见 luaL_Buffer)。将字符串复制到此空间后,您必须使用字符串的大小调用 `luaL_addsize`(参见 luaL_addsize())以将其实际添加到缓冲区。
luaL_pushresult luaL_pushresult()
void luaL_pushresult (luaL_Buffer *B);
完成对缓冲区 `B` 的使用,将最终字符串留在堆栈的顶部。
luaL_ref luaL_ref()
int luaL_ref (lua_State *L, int t);
在索引 `t` 处的表中为堆栈顶部的对象创建并返回一个 `reference`(并弹出该对象)。
引用是一个唯一的整数键。只要您不手动将整数键添加到表 `t` 中,`luaL_ref` 就会确保它返回的键的唯一性。您可以通过调用 `lua_rawgeti(L, t, r)`(参见 lua_rawgeti())来检索由引用 `r` 引用的对象。函数 `luaL_unref`(参见 luaL_unref())释放引用及其关联的对象。
如果堆栈顶部的对象为 `nil`,则 `luaL_ref` 返回常量 `LUA_REFNIL`。常量 `LUA_NOREF` 保证与 `luaL_ref` 返回的任何引用不同。
luaL_Reg luaL_Reg
typedef struct luaL_Reg {
    const char *name;
    lua_CFunction func;
} luaL_Reg;
要由 `luaL_register`(参见 luaL_register())注册的函数数组的类型。`name` 是函数名,`func` 是指向函数的指针。任何 `luaL_Reg` 数组都必须以一个哨兵条目结束,其中 `name` 和 `func` 都为 `NULL`。
luaL_register luaL_register()
void luaL_register (lua_State *L,
                    const char *libname,
                    const luaL_Reg *l);
打开一个库。
当 `libname` 等于 `NULL` 时,它只是将列表 `l`(参见 luaL_Reg)中的所有函数注册到堆栈顶部的表中。
当使用非空 `libname` 调用时,`luaL_register` 会创建一个新的表 `t`,将其设置为全局变量 `libname` 的值,将其设置为 `package.loaded[libname]` 的值,并在其中注册列表 `l` 中的所有函数。如果 `package.loaded[libname]` 或变量 `libname` 中存在表,则会重用此表,而不是创建新的表。
在任何情况下,该函数都会将该表留在堆栈的顶部。
luaL_typename luaL_typename()
const char *luaL_typename (lua_State *L, int idx);
返回索引 `idx` 处的值的类型的名称。
luaL_typerror luaL_typerror()
int luaL_typerror (lua_State *L, int narg, const char *tname);
生成一条类似于以下内容的错误消息
location : bad argument narg to 'func' ( tname expected, got rt )
其中 `location` 由 `luaL_where` 生成(参见 luaL_where()),`func` 是当前函数的名称,`rt` 是实际参数的类型名称。
luaL_unref luaL_unref()
void luaL_unref (lua_State *L, int t, int ref);
从索引 `t` 处的表中释放引用 `ref`(参见 luaL_ref())。该条目将从表中删除,以便可以收集引用的对象。引用 `ref` 也将被释放以供再次使用。
如果 `ref` 为 `LUA_NOREF` 或 `LUA_REFNIL`,则 `luaL_unref` 不会执行任何操作。
luaL_where luaL_where()
void luaL_where (lua_State *L, int lvl);
将一个字符串推送到堆栈中,该字符串标识调用堆栈中级别 `lvl` 处的控制的当前位置。通常,此字符串具有以下格式
chunkname:currentline
级别 0 是正在运行的函数,级别 1 是调用正在运行的函数的函数,等等。
此函数用于构建错误消息的前缀。

5 标准库 lua-lib

标准库提供一些有用的函数,这些函数是直接通过 C API 实现的。其中一些函数为语言提供了基本的服务(例如,`type` 和 `getmetatable`);其他函数提供对“外部”服务的访问(例如,I/O);还有一些函数可以在 Lua 本身中实现,但非常有用或具有需要使用 C 实现的性能要求(例如,`sort`)。
所有库都是通过官方 C API 实现的,并作为单独的 C 模块提供。目前,Lua 有以下标准库
基本库;
包库;
字符串操作;
表操作;
数学函数(sin、log 等);
输入和输出;
操作系统功能;
调试功能。
除了基本库和包库之外,每个库都将其所有函数作为全局表的字段或其对象的成员提供。
lua-openlibs
要访问这些库,C 宿主程序应该调用 `luaL_openlibs` 函数,该函数会打开所有标准库(参见 luaL_openlibs())。或者,宿主程序可以通过调用 `luaopen_base`(对于基本库)、`luaopen_package`(对于包库)、`luaopen_string`(对于字符串库)、`luaopen_table`(对于表库)、`luaopen_math`(对于数学库)、`luaopen_io`(对于 I/O 和操作系统库)和 `luaopen_debug`(对于调试库)来单独打开库。这些函数在 `lualib.h` 中声明,不应直接调用:您必须像调用任何其他 Lua C 函数一样调用它们,例如,使用 `lua_call`(参见 lua_call())。

5.1 基本函数 lua-lib-core

基本库为 Lua 提供了一些核心函数。如果您在应用程序中不包含此库,则应仔细检查您是否需要为其某些功能提供实现。
assert({v} [, {message}]) assert()
当其参数 `v` 的值为假(即,`nil` 或 `false`)时,会引发错误;否则,返回其所有参数。`message` 是错误消息;如果缺失,则默认为“assertion failed!”。
collectgarbage({opt} [, {arg}]) collectgarbage()
此函数是垃圾回收器的通用接口。它根据第一个参数 `{opt}` 执行不同的功能
"stop" 停止垃圾回收器。"restart" 重新启动垃圾回收器。"collect" 执行完整的垃圾回收周期。"count" 返回 Lua 使用的总内存(以 KB 为单位)。"step" 执行垃圾回收步骤。步骤“大小”由 `{arg}` 控制(较大的值意味着更多步骤),以未指定的方式进行。如果您想控制步骤大小,则必须通过实验调整 `{arg}` 的值。如果步骤完成了一个收集周期,则返回 `true`。"setpause" 将 `{arg}` /100 设置为收集器 `pause` 的新值(参见 lua-gc)。"setstepmul" 将 `{arg}` /100 设置为收集器 `step multiplier` 的新值(参见 lua-gc)。
dofile({filename}) dofile()
打开命名文件并执行其内容作为 Lua 代码块。在不带参数调用时,`dofile` 会执行标准输入 (stdin) 的内容。返回代码块返回的所有值。如果发生错误,`dofile` 会将错误传播到其调用者(即,`dofile` 不会在受保护模式下运行)。
error({message} [, {level}]) error()
终止最后调用的受保护函数,并将 `message` 作为错误消息返回。函数 `{error}` 永远不会返回。
通常, `{error}` 会在消息开头添加一些有关错误位置的信息。参数 `{level}` 指定如何获取错误位置。级别 1(默认)使用 `{error}` 函数被调用的位置作为错误位置。级别 2 将错误指向调用 `{error}` 的函数被调用的位置;依此类推。传递级别 0 会避免将错误位置信息添加到消息中。
_G _G
一个全局变量(而不是函数),它保存全局环境(即,`_G._G = _G`)。Lua 本身不使用此变量;更改其值不会影响任何环境,反之亦然。(使用 `setfenv` 来更改环境。)
getfenv({f}) getfenv()
返回函数使用的当前环境。 `{f}` 可以是 Lua 函数,也可以是指定该堆栈级别上的函数的数字:级别 1 是调用 `getfenv` 的函数。如果给定的函数不是 Lua 函数,或者 `{f}` 为 0,则 `getfenv` 返回全局环境。 `{f}` 的默认值为 1。
getmetatable({object}) getmetatable()
如果{object}没有元表,则返回nil。 否则,如果对象的元表具有"__metatable"字段,则返回关联的值。 否则,返回给定对象的元表。
ipairs({t}) ipairs()
返回三个值:一个迭代器函数、表{t}和0,因此构造
for i,v in ipairs(t) do body end
将迭代所有对(1,t[1]),(2,t[2]),...,直到表中第一个缺失的整数键。
load({func} [, {chunkname}]) load()
使用函数{func}加载一个块以获取其片段。 对{func}的每次调用都必须返回一个字符串,该字符串与之前的结果连接。 返回nil(或无值)表示块的结束。
如果没有错误,则返回编译后的块作为函数;否则,返回nil以及错误消息。 返回函数的环境是全局环境。
{chunkname}用作错误消息和调试信息的块名称。
loadfile([{filename}]) loadfile()
类似于load(参见 load()),但从文件{filename}或标准输入(如果没有给出文件名)获取块。
loadstring({string} [, {chunkname}]) loadstring()
类似于load(参见 load()),但从给定的{string}获取块。
要加载并运行给定的字符串,请使用以下习惯用法
assert(loadstring(s))()
next({table} [, {index}]) next()
允许程序遍历表的全部字段。 它的第一个参数是表,它的第二个参数是该表中的索引。 next返回表的下一个索引及其关联的值。 当以nil作为其第二个参数调用时,next返回初始索引及其关联的值。 当以最后一个索引或在空表中以nil调用时,next返回nil。 如果第二个参数不存在,则将其解释为nil。 特别是,您可以使用next(t)来检查表是否为空。
枚举索引的顺序未指定,即使对于数字索引也是如此。(要按数字顺序遍历表,请使用数字foripairs()函数。)
如果在遍历期间,您将任何值分配给表中不存在的字段,则next的行为是未定义的。 然而,您可以修改现有字段。 特别是,您可以清除现有字段。
pairs({t}) pairs()
返回三个值:next()函数、表{t}nil,因此构造
for k,v in pairs(t) do body end
将迭代表{t}的所有键值对。
pcall({f}, {arg1}, {...}) pcall()
保护模式下使用给定的参数调用函数{f}。 这意味着{f}内部的任何错误都不会传播;相反,pcall捕获错误并返回一个状态代码。 它的第一个结果是状态代码(一个布尔值),如果调用成功且没有错误,则为true。 在这种情况下,pcall还会在第一个结果之后返回调用中的所有结果。 在发生任何错误的情况下,pcall返回false以及错误消息。
print({...}) print()
接收任意数量的参数,并将它们的值打印到stdout,使用tostring tostring()函数将它们转换为字符串。 print并非旨在用于格式化输出,而仅仅是一种快速显示值的方法,通常用于调试。 对于格式化输出,请使用string.format(参见 string.format())。
rawequal({v1}, {v2}) rawequal()
检查{v1}是否等于{v2},不调用任何元方法。 返回一个布尔值。
rawget({table}, {index}) rawget()
获取table[index]的实际值,不调用任何元方法。 {table}必须是一个表;{index}可以是任何值。
rawset({table}, {index}, {value}) rawset()
table[index]的实际值设置为{value},不调用任何元方法。 {table}必须是一个表,{index}任何与nil不同的值,{value}任何 Lua 值。
此函数返回{table}
select({index}, {...}) select()
如果{index}是数字,则返回参数编号{index}之后的所有参数。 否则,{index}必须是字符串"#",并且select返回它接收的额外参数的总数。
setfenv({f}, {table}) setfenv()
设置要由给定函数使用的环境。 {f}可以是 Lua 函数,也可以是指定该堆栈级别上函数的数字:级别 1 是调用setfenv的函数。 setfenv返回给定的函数。
作为特殊情况,当{f}为 0 时,setfenv更改运行线程的环境。 在这种情况下,setfenv不返回值。
setmetatable({table}, {metatable}) setmetatable()
为给定的表设置元表。(您不能从 Lua 中更改其他类型的元表,只能从 C 中更改。)如果{metatable}nil,则删除给定表的元表。 如果原始元表具有"__metatable"字段,则会引发错误。
此函数返回{table}
tonumber({e} [, {base}]) tonumber()
尝试将它的参数转换为数字。 如果参数已经是数字或可转换为数字的字符串,则tonumber返回此数字;否则,它返回nil
可选参数指定解释数字的基数。 基数可以是 2 到 36 之间的任何整数,包括 2 和 36。 在高于 10 的基数中,字母A(大小写均可)表示 10,B表示 11,依此类推,Z'表示 35。 在基数 10(默认值)中,数字可以有小数部分,以及可选的指数部分(参见 lua-lexical)。 在其他基数中,只接受无符号整数。
tostring({e}) tostring()
接收任何类型的参数并将其转换为合理格式的字符串。 为了完全控制数字的转换方式,请使用string.format(参见 string.format())。
__tostring
如果{e}的元表具有"__tostring"字段,则tostring调用相应的值,并将{e}作为参数,并将调用的结果用作其结果。
type({v}) lua-type()
返回其唯一参数的类型,编码为字符串。 此函数的可能结果是"nil"(一个字符串,而不是值nil),"number""string""boolean"table""function""thread""userdata"
unpack({list} [, {i} [, {j}]]) unpack()
返回给定表中的元素。 此函数等效于
return list[i], list[i+1], ..., list[j]
除了上面的代码只能针对固定数量的元素编写。 默认情况下,{i}为 1,{j}为列表的长度,如长度运算符定义(参见 lua-length)。
_VERSION _VERSION
一个全局变量(而不是函数),它保存一个包含当前解释器版本的字符串。 此字符串的当前内容是"Lua 5.1"
xpcall({f}, {err}) xpcall()
此函数类似于pcall(参见 pcall()),不同之处在于您可以设置新的错误处理程序。
xpcall在保护模式下调用函数{f},使用{err}作为错误处理程序。 {f}内部的任何错误都不会传播;相反,xpcall捕获错误,使用原始错误对象调用{err}函数,并返回一个状态代码。 它的第一个结果是状态代码(一个布尔值),如果调用成功且没有错误,则为 true。 在这种情况下,xpcall还会在第一个结果之后返回调用中的所有结果。 在发生任何错误的情况下,xpcall返回false以及{err}的结果。

5.2 协程操作 lua-lib-coroutine

与协程相关的操作构成了基本库的子库,并位于表coroutine中。 有关协程的常规描述,请参见 lua-coroutine
coroutine.create({f}) coroutine.create()
创建一个新的协程,其主体为{f}{f}必须是 Lua 函数。 返回此新协程,一个类型为"thread"的对象。
coroutine.resume({co} [, {val1}, {...}]) coroutine.resume()
启动或继续协程{co}的执行。 第一次恢复协程时,它将开始运行其主体。 值{val1}{...}作为参数传递给主体函数。 如果协程已让出,则resume会重新启动它;值{val1}{...}作为让出的结果传递。
如果协程在没有错误的情况下运行,则resume返回true以及传递给yield的任何值(如果协程让出)或主体函数返回的任何值(如果协程终止)。 如果有任何错误,resume返回false以及错误消息。
coroutine.running() coroutine.running()
返回正在运行的协程,或在主线程调用时返回nil
coroutine.status({co}) coroutine.status()
返回协程{co}的状态,作为字符串:"running",如果协程正在运行(即,它调用了status);"suspended",如果协程已暂停在对yield的调用中,或者它尚未开始运行;"normal",如果协程处于活动状态但未运行(即,它已恢复另一个协程);以及"dead",如果协程已完成其主体函数,或者它已停止并出现错误。
coroutine.wrap({f}) coroutine.wrap()
创建一个新的协程,其主体为{f}{f}必须是 Lua 函数。 返回一个函数,该函数每次被调用时都会恢复协程。 传递给函数的任何参数都将作为对resume的额外参数进行处理。 返回resume返回的相同值,除了第一个布尔值。 在发生错误的情况下,传播错误。
coroutine.yield({...}) coroutine.yield()
暂停调用协程的执行。 协程不能运行 C 函数、元方法或迭代器。 传递给yield的任何参数都将作为对resume的额外结果传递。

5.3 模块 lua-modules

包库提供了在 Lua 中加载和构建模块的基本设施。它直接在全局环境中导出其两个函数:requiremodule(参见 require()module())。其他所有内容都导出到表 package 中。
module({name} [, {...}]) module()
创建一个模块。如果 package.loaded[name] 中存在一个表,则此表为模块。否则,如果存在具有给定名称的全局表 t,则此表为模块。否则,创建一个新表 t 并将其设置为全局 {name} 的值和 package.loaded[name] 的值。此函数还将 t._NAME 初始化为给定名称,将 t._M 初始化为模块(t 本身),并将 t._PACKAGE 初始化为包名称(完整模块名称减去最后一个组件;见下文)。最后,modulet 设置为当前函数的新环境和 package.loaded[name] 的新值,以便 require() 返回 t
如果 {name} 是一个复合名称(即一个由点分隔的组件名称),则 module 为每个组件创建(或如果已存在,则重用)表。例如,如果 {name}a.b.c,则 module 将模块表存储在全局 ab 字段的 c 字段中。
此函数可以在模块名称之后接收可选的 options,其中每个选项都是要应用于模块的函数。
require({modname}) require()
加载给定的模块。该函数首先查看 package.loaded 表以确定 {modname} 是否已加载。如果是,则 require 返回存储在 package.loaded[modname] 中的值。否则,它将尝试为模块查找 loader
要查找加载器,require 首先查询 package.preload[modname]。如果它具有值,则此值(应为函数)为加载器。否则,require 将使用存储在 package.path 中的路径搜索 Lua 加载器。如果这也失败,它将使用存储在 package.cpath 中的路径搜索 C 加载器。如果这也失败,它将尝试使用 all-in-one 加载器(见下文)。
加载 C 库时,require 首先使用动态链接设施将应用程序与库链接。然后,它尝试在此库中查找一个用作加载器的 C 函数。此 C 函数的名称是字符串 "luaopen_" 与模块名称的副本(其中每个点都被下划线替换)连接而成。此外,如果模块名称包含连字符,则会删除其前缀(直到且包括第一个连字符)。例如,如果模块名称是 a.v1-b.c,则函数名称将为 luaopen_b_c
如果 require 未为模块找到 Lua 库或 C 库,则它将调用 all-in-one 加载器。此加载器在 C 路径中搜索给定模块的根名称的库。例如,在需要 a.b.c 时,它将搜索 a 的 C 库。如果找到,它将在其中查找子模块的打开函数;在我们的示例中,这将是 luaopen_a_b_c。通过此功能,一个包可以将多个 C 子模块打包到一个库中,每个子模块保留其原始的打开函数。
找到加载器后,require 将使用单个参数 {modname} 调用加载器。如果加载器返回任何值,require 将返回值分配给 package.loaded[modname]。如果加载器未返回值并且未将任何值分配给 package.loaded[modname],则 requiretrue 分配给此条目。在任何情况下,require 都将返回 package.loaded[modname] 的最终值。
如果加载或运行模块时出现任何错误,或者如果它找不到模块的任何加载器,则 require 将发出错误信号。
package.cpath package.cpath
require 用于搜索 C 加载器的路径。
Lua 以与初始化 Lua 路径 package.path 相同的方式初始化 C 路径 package.cpath,使用环境变量 LUA_CPATH(以及在 luaconf.h 中定义的另一个默认路径)。
package.loaded package.loaded()
require 用于控制哪些模块已加载的表。当您需要一个模块 modname 并且 package.loaded[modname] 不为假时,require 只会返回存储在那里的值。
package.loadlib({libname}, {funcname}) package.loadlib()
将主机程序与 C 库 {libname} 动态链接。在此库中,查找函数 {funcname} 并将其作为 C 函数返回。(因此,{funcname} 必须遵循协议(参见 lua_CFunction)。
这是一个低级函数。它完全绕过包和模块系统。与 require 不同,它不执行任何路径搜索,也不自动添加扩展名。{libname} 必须是 C 库的完整文件名,包括必要时路径和扩展名。{funcname} 必须是 C 库导出的确切名称(这可能取决于使用的 C 编译器和链接器)。
此函数不受 ANSI C 支持。因此,它只在某些平台(Windows、Linux、Mac OS X、Solaris、BSD 以及支持 dlfcn 标准的其他 Unix 系统)上可用。
package.path package.path
require 用于搜索 Lua 加载器的路径。
在启动时,Lua 使用环境变量 LUA_PATH 的值或在 luaconf.h 中定义的默认路径(如果环境变量未定义)初始化此变量。环境变量值中的任何 ";;" 都将被默认路径替换。
路径是由分号分隔的 templates 序列。对于每个模板,require 将使用 filename(即 modname,其中每个点都被替换为“目录分隔符”(如 Unix 中的 "/"))将模板中的每个问号更改;然后它将尝试加载结果文件名。因此,例如,如果 Lua 路径是
"./?.lua;./?.lc;/usr/local/?/init.lua"
则搜索模块 foo 的 Lua 加载器将尝试加载文件 ./foo.lua./foo.lc/usr/local/foo/init.lua,按此顺序。
package.preload package.preload()
用于存储特定模块加载器的表(参见 require())。
package.seeall({module}) package.seeall()
{module} 设置一个元表,其 __index 字段引用全局环境,以便此模块继承全局环境的值。用作函数 {module} 的选项。

5.4 字符串操作 lua-lib-string

此库提供了用于字符串操作的通用函数,例如查找和提取子字符串以及模式匹配。在 Lua 中对字符串进行索引时,第一个字符位于位置 1(不是位置 0,如 C 中)。索引可以为负数,并解释为从字符串的末尾反向索引。因此,最后一个字符位于位置 -1,依此类推。
字符串库在其表 string 中提供所有函数。它还为字符串设置了一个元表,其中 __index 字段指向 string 表。因此,您可以以面向对象的方式使用字符串函数。例如,string.byte(s, i) 可以写成 s:byte(i)
string.byte({s} [, {i} [, {j}]]) string.byte()
返回字符 s[i]s[i+1]、...、s[j] 的内部数值代码。{i} 的默认值为 1;{j} 的默认值为 {i}
请注意,数值代码在不同平台之间不一定是可移植的。
string.char({...}) string.char()
接收零个或多个整数。返回一个字符串,其长度等于参数的数量,其中每个字符的内部数值代码等于其对应参数。
请注意,数值代码在不同平台之间不一定是可移植的。
string.dump({function}) string.dump()
返回一个包含给定函数的二进制表示的字符串,以便稍后对该字符串进行 loadstring() 将返回该函数的副本。{function} 必须是一个没有上值的 Lua 函数。
string.find({s}, {pattern} [, {init} [, {plain}]]) string.find()
在字符串 {s} 中查找 {pattern} 的第一个匹配项。如果找到匹配项,则 {find} 将返回 {s} 中此匹配项开始和结束的索引;否则,它将返回 nil。第三个可选的数值参数 {init} 指定开始搜索的位置;其默认值为 1,可以为负数。作为第四个可选参数的 {true}{plain} 将关闭模式匹配功能,因此该函数执行简单的“查找子字符串”操作,{pattern} 中没有任何字符被视为“魔法”。请注意,如果给出 {plain},则也必须给出 {init}
如果模式包含捕获,则在成功匹配时,捕获的值也将返回,位于两个索引之后。
string.format({formatstring}, {...}) string.format()
返回其可变数量的参数的格式化版本,遵循其第一个参数(必须是字符串)中给出的描述。格式字符串遵循与标准 C 函数的 printf 家族相同的规则。唯一的区别是,选项/修饰符 *lLnph 不受支持,并且还有一个额外的选项 qq 选项以适合安全读取回 Lua 解释器的形式格式化字符串:字符串写到双引号之间,并且字符串中的所有双引号、换行符、嵌入的零和反斜杠在写入时都会正确地转义。例如,调用
string.format('%q', 'a string with "quotes" and \n new line')
将生成字符串
"a string with \"quotes\" and \
 new line"
选项 cdEefgGiouXx 都期望一个数字作为参数,而 qs 期望一个字符串。
此函数不接受包含嵌入的零的字符串值。
string.gmatch({s}, {pattern}) string.gmatch()
返回一个 迭代器 函数,该函数每次被调用时,都会返回字符串 {s}{pattern} 的下一个捕获。
如果 {pattern} 没有指定捕获,则每次调用时都会生成整个匹配项。
例如,以下循环
s = "hello world from Lua"
for w in string.gmatch(s, "%a+") do
  print(w)
end
将遍历字符串 {s} 中的所有单词,每行打印一个单词。下一个示例将给定字符串中的所有 key=value 对收集到一个表中
t = {}
s = "from=world, to=Lua"
for k, v in string.gmatch(s, "(%w+)=(%w+)") do
  t[k] = v
end
string.gsub({s}, {pattern}, {repl} [, {n}]) string.gsub()
返回 {s} 的副本,其中 {pattern} 的所有匹配项都被 {repl} 指定的替换字符串替换,{repl} 可以是字符串、表或函数。gsub 还将其第二个值作为返回值,即已进行的替换总数。
如果 {repl} 是一个字符串,则使用其值进行替换。字符 % 作为转义字符:{repl} 中任何形式为 %n 的序列,其中 {n} 在 1 到 9 之间,代表第 {n} 个捕获子字符串的值(见下文)。序列 %0 代表整个匹配项。序列 %% 代表单个 %
如果 {repl} 是一个表,则使用第一个捕获作为键,对每个匹配项查询该表;如果模式未指定任何捕获,则使用整个匹配项作为键。
如果 {repl} 是一个函数,则每次发生匹配时都会调用此函数,并将所有捕获的子字符串按顺序作为参数传递;如果模式未指定任何捕获,则将整个匹配项作为唯一参数传递。
如果表查询或函数调用返回的值是字符串或数字,则将其用作替换字符串;否则,如果它是 falsenil,则不进行替换(即,字符串中的原始匹配项保留)。
可选的最后一个参数 {n} 限制了发生替换的最大次数。例如,当 {n} 为 1 时,只替换 pattern 的第一个出现。
以下是一些示例
x = string.gsub("hello world", "(%w+)", "%1 %1")
--> x="hello hello world world"
x = string.gsub("hello world", "%w+", "%0 %0", 1)
--> x="hello hello world"
x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
--> x="world hello Lua from"
x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
--> x="home = /home/roberto, user = roberto"
x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
      return loadstring(s)()
    end)
--> x="4+5 = 9"
local t = {name="lua", version="5.1"}
x = string.gsub("$name%-$version.tar.gz", "%$(%w+)", t)
--> x="lua-5.1.tar.gz"
string.len({s}) string.len()
接收一个字符串并返回其长度。空字符串 "" 的长度为 0。嵌入的零会被计算在内,因此 "a\000b\000c" 的长度为 5。
string.lower({s}) string.lower()
接收一个字符串并返回该字符串的副本,其中所有大写字母都改为小写。所有其他字符保持不变。大写字母的定义取决于当前区域设置。
string.match({s}, {pattern} [, {init}]) string.match()
在字符串 {s} 中查找 {pattern} 的第一个 match。如果找到,则 match 返回模式中的捕获;否则返回 nil。如果 {pattern} 未指定任何捕获,则返回整个匹配项。第三个可选的数字参数 {init} 指定搜索的起点;其默认值为 1,可以为负数。
string.rep({s}, {n}) string.rep()
返回一个字符串,该字符串是 {n} 个字符串 {s} 副本的串联。
string.reverse({s}) string.reverse()
返回一个字符串,该字符串是字符串 {s} 的反转。
string.sub({s}, {i} [, {j}]) string.sub()
返回 {s} 的子字符串,该子字符串从 {i} 开始,一直持续到 {j}{i}{j} 可以为负数。如果 {j} 缺失,则假定它等于 -1(与字符串长度相同)。特别是,调用 string.sub(s,1,j) 返回 {s} 的长度为 {j} 的前缀,而 string.sub(s,-i) 返回 {s} 的长度为 {i} 的后缀。
string.upper({s}) string.upper()
接收一个字符串并返回该字符串的副本,其中所有小写字母都改为大写。所有其他字符保持不变。小写字母的定义取决于当前区域设置。

5.4.1 模式 lua-patterns

字符类用于表示一组字符。以下组合允许在描述字符类时使用
x(其中 x 不是魔法字符 ^$()%.[]*+-? 之一)代表字符 x 本身。
.(点)代表所有字符。
%a 代表所有字母。
%c 代表所有控制字符。
%d 代表所有数字。
%l 代表所有小写字母。
%p 代表所有标点符号字符。
%s 代表所有空格字符。
%u 代表所有大写字母。
%w 代表所有字母数字字符。
%x 代表所有十六进制数字。
%z 代表表示为 0 的字符。
%x(其中 x 是任何非字母数字字符)代表字符 x。这是转义魔法字符的标准方法。任何标点符号字符(即使是非魔法字符)都可以在用作模式中的自身表示时,在其前面加上 %
[set] 代表所有字符的并集,这些字符都在 set 中。可以通过使用 - 分隔范围的结束字符来指定字符范围。所有前面描述的类 %x 也可以用作 set 中的组件。set 中的所有其他字符都代表自身。例如,[%w_](或 [_%w])代表所有字母数字字符加上下划线,[0-7] 代表八进制数字,而 [0-7%l%-] 代表八进制数字加上小写字母加上 - 字符。
范围和类之间的交互没有定义。因此,像 [%a-z][a-%%] 这样的模式没有意义。
[^set] 代表 set 的补集,其中 set 的解释如上所述。
对于所有由单个字母表示的类(%a%c 等),相应的大写字母代表该类的补集。例如,%S 代表所有非空格字符。
字母、空格和其他字符组的定义取决于当前区域设置。特别是,类 [a-z] 可能不等于 %l

模式项 lua-patternitem

模式项可以是
单个字符类,匹配该类中的任何单个字符;
单个字符类后面跟着 *,匹配该类中 0 个或多个字符的重复。这些重复项将始终匹配最长的可能序列;
单个字符类后面跟着 +,匹配该类中 1 个或多个字符的重复。这些重复项将始终匹配最长的可能序列;
单个字符类后面跟着 -,也匹配该类中 0 个或多个字符的重复。与 * 不同,这些重复项将始终匹配最短的可能序列;
单个字符类后面跟着 ?,匹配该类中 0 个或 1 个字符的出现;
%n,对于 n 在 1 到 9 之间;此项匹配等于第 n 个捕获字符串的子字符串(见下文);
%bxy,其中 xy 是两个不同的字符;此项匹配以 x 开头、以 y 结尾的字符串,并且 xy 是平衡的。这意味着,如果从左到右读取字符串,对 x 计数 +1,对 y 计数 -1,则结尾的 y 是计数达到 0 的第一个 y。例如,项 %b() 匹配具有平衡括号的表达式。

模式 lua-pattern

模式是模式项的序列。模式开头的 ^ 将匹配锚定在主题字符串的开头。模式结尾的 $ 将匹配锚定在主题字符串的结尾。在其他位置,^$ 没有特殊含义,代表自身。

捕获 lua-capture

模式可能包含用括号括起来的子模式;它们描述捕获。匹配成功时,与捕获匹配的主题字符串的子字符串将被存储(捕获)以供将来使用。捕获根据其左括号的顺序编号。例如,在模式 "(a*(.)%w(%s*))" 中,与 "a*(.)%w(%s*)" 匹配的字符串部分存储为第一个捕获(因此编号为 1);与 . 匹配的字符捕获编号为 2,与 %s* 匹配的部分编号为 3。
作为特例,空捕获 () 捕获当前字符串位置(一个数字)。例如,如果我们在字符串 "flaaap" 上应用模式 "()aa()",将有两个捕获:3 和 5。
模式不能包含嵌入的零。请使用 %z 代替。

5.5 表操作 lua-lib-table

此库提供用于表操作的通用函数。它在表 table 中提供所有函数。
表库中的大多数函数都假设该表表示一个数组或一个列表。对于这些函数,当我们谈论表的“长度”时,我们指的是长度运算符的结果。
table.concat({table} [, {sep} [, {i} [, {j}]]]) table.concat()
给定一个数组,其中所有元素都是字符串或数字,返回 table[i]..sep..table[i+1] ... sep..table[j]{sep} 的默认值为空字符串,{i} 的默认值为 1,{j} 的默认值为表的长度。如果 {i} 大于 {j},则返回空字符串。
table.foreach({table}, {f}) table.foreach()
{table} 中的所有元素执行给定的 {f}。对于每个元素,{f} 使用索引和相应的值作为参数被调用。如果 {f} 返回一个非 nil 值,则循环被中断,并且此值将作为 table.foreach 的最终值返回。
有关表遍历的更多信息,请参阅 next()
table.foreachi({table}, {f}) table.foreachi()
{table} 的数字索引执行给定的 {f}。对于每个索引,{f} 使用索引和相应的值作为参数被调用。索引按顺序访问,从 1 到 n,其中 n 是表的长度。如果 {f} 返回一个非 nil 值,则循环被中断,并且此值将作为 table.foreachi 的结果返回。
table.insert({table}, [{pos},] {value}) table.insert()
{table} 中的 {pos} 位置插入元素 {value},如有必要,将其他元素向上移动以腾出空间。{pos} 的默认值为 n+1,其中 n 是表的长度(见 lua-length),因此调用 table.insert(t,x) 会在表 t 的末尾插入 x
table.maxn({table}) table.maxn()
返回给定表的最大正数数字索引,如果表没有正数数字索引,则返回零。(为了完成其工作,此函数会对整个表进行线性遍历。)
table.remove({table} [, {pos}]) table.remove()
{table} 中删除 {pos} 位置的元素,如有必要,将其他元素向下移动以关闭空间。返回被删除元素的值。{pos} 的默认值为 n,其中 n 是表的长度(见 lua-length),因此调用 table.remove(t) 会删除表 t 的最后一个元素。
table.sort({table} [, {comp}]) table.sort()
对表元素进行排序,按照给定的顺序,就地排序,从 table[1]table[n],其中 n 是表的长度(参见 lua-length)。如果给出了 {comp},则它必须是一个接收两个表元素并返回第一个元素小于第二个元素时为真的函数(这样在排序后 not comp(a[i+1],a[i]) 为真)。如果没有给出 {comp},则使用标准 Lua 运算符 < 代替。
排序算法不是稳定的,也就是说,由给定顺序认为相等的元素可能在排序后改变其相对位置。

5.6 数学函数 lua-lib-math

该库是标准 C 数学库的大多数函数的接口。它在表 math 中提供所有函数。
math.abs({x}) math.abs()
返回 {x} 的绝对值。
math.acos({x}) math.acos()
返回 {x} 的反余弦(以弧度表示)。
math.asin({x}) math.asin()
返回 {x} 的反正弦(以弧度表示)。
math.atan({x}) math.atan()
返回 {x} 的反正切(以弧度表示)。
math.atan2({x}, {y}) math.atan2()
返回 x/y 的反正切(以弧度表示),但使用两个参数的符号来确定结果的象限。(它还正确处理了 {y} 为零的情况。)
math.ceil({x}) math.ceil()
返回大于或等于 {x} 的最小整数。
math.cos({x}) math.cos()
返回 {x} 的余弦(假设为弧度)。
math.cosh({x}) math.cosh()
返回 {x} 的双曲余弦。
math.deg({x}) math.deg()
返回以弧度表示的角度 {x} 的度数。
math.exp({x}) math.exp()
返回值 e^x
math.floor({x}) math.floor()
返回小于或等于 {x} 的最大整数。
math.fmod({x}, {y}) math.fmod()
返回 {x} 除以 {y} 的余数。
math.frexp({x}) math.frexp()
返回 me,使得 x = m * 2^ee 是一个整数,m 的绝对值在 [0.5, 1) 范围内(或当 {x} 为零时为零)。
math.huge math.huge
HUGE_VAL,一个大于或等于任何其他数值的值。
math.ldexp({m}, {e}) math.ldexp()
返回 m * 2^ee 应该是一个整数)。
math.log({x}) math.log()
返回 {x} 的自然对数。
math.log10({x}) math.log10()
返回 {x} 的以 10 为底的对数。
math.max({x}, {...}) math.max()
返回其参数中的最大值。
math.min({x}, {...}) math.min()
返回其参数中的最小值。
math.modf({x}) math.modf()
返回两个数字,{x} 的整数部分和 {x} 的小数部分。
math.pi math.pi
pi 的值。
math.pow({x}, {y}) math.pow()
返回 x^y。(您也可以使用表达式 x^y 来计算此值。)
math.rad({x}) math.rad()
返回以度数表示的角度 {x} 的弧度。
math.random([{m} [, {n}]]) math.random()
此函数是 ANSI C 提供的简单伪随机生成器函数 rand 的接口。(不能保证其统计特性。)
当不带参数调用时,返回 [0,1) 范围内的伪随机实数。当带一个数字 {m} 调用时,math.random 返回 [1, m] 范围内的伪随机整数。当带两个数字 {m}{n} 调用时,math.random 返回 [m, n] 范围内的伪随机整数。
math.randomseed({x}) math.randomseed()
{x} 设置为伪随机生成器的“种子”:相同的种子产生相同序列的数字。
math.sin({x}) math.sin()
返回 {x} 的正弦(假设为弧度)。
math.sinh({x}) math.sinh()
返回 {x} 的双曲正弦。
math.sqrt({x}) math.sqrt()
返回 {x} 的平方根。(您也可以使用表达式 x^0.5 来计算此值。)
math.tan({x}) math.tan()
返回 {x} 的正切(假设为弧度)。
math.tanh({x}) math.tanh()
返回 {x} 的双曲正切。

5.6 输入和输出设施 lua-lib-io

I/O 库提供两种不同的文件操作方式。第一种使用隐式文件描述符;也就是说,存在操作来设置默认输入文件和默认输出文件,所有输入/输出操作都针对这些默认文件。第二种方式使用显式文件描述符。
当使用隐式文件描述符时,所有操作都由表 io 提供。当使用显式文件描述符时,操作 io.open 返回一个文件描述符,然后所有操作都作为文件描述符的方法提供。
io 还提供三个预定义的文件描述符,其含义与 C 中的通常含义相同:io.stdinio.stdoutio.stderr
除非另有说明,所有 I/O 函数在失败时返回 nil(以及错误消息作为第二个结果),并在成功时返回一些与 nil 不同的值。
io.close([{file}]) io.close()
等效于 file:close。如果没有 {file},则关闭默认输出文件。
io.flush() io.flush()
等效于对默认输出文件执行 file:flush
io.input([{file}]) io.input()
当带文件名调用时,它打开命名文件(在文本模式下),并将其句柄设置为默认输入文件。当带文件句柄调用时,它只将此文件句柄设置为默认输入文件。当不带参数调用时,它返回当前默认输入文件。
如果发生错误,此函数将引发错误,而不是返回错误代码。
io.lines([{filename}]) io.lines()
以读模式打开给定的文件名,并返回一个 迭代器 函数,每次调用该函数时,它都会从文件中返回一行。因此,构造
for line in io.lines(filename) do body end
将迭代文件中的所有行。当迭代器函数检测到文件结束时,它将返回 nil(以结束循环)并自动关闭文件。
调用 io.lines()(不带文件名)等效于 io.input():lines();也就是说,它迭代默认输入文件中的行。在这种情况下,它在循环结束时不会关闭文件。
io.open({filename} [, {mode}]) io.open()
此函数以字符串 {mode} 中指定的模式打开文件。它返回一个新的文件句柄,或在发生错误时返回 nil 以及错误消息。
{mode} 字符串可以是以下任何一种
"r" 读模式(默认);
"w" 写模式;
"a" 追加模式;
"r+" 更新模式,所有以前的数据都保留;
"w+" 更新模式,所有以前的数据都将被擦除;
"a+" 追加更新模式,保留以前的数据,写入仅允许在文件末尾进行。
{mode} 字符串的末尾也可能有一个 b,这在某些系统中是必要的,以便以二进制模式打开文件。此字符串与标准 C 函数 fopen 中使用的字符串完全相同。
io.output([{file}]) io.output()
类似于 io.input,但对默认输出文件进行操作。
io.popen({prog} [, {mode}]) io.popen()
在分离的进程中启动程序 {prog} 并返回一个文件句柄,您可以使用它从该程序读取数据(如果 {mode}"r",则为默认值)或向该程序写入数据(如果 {mode}"w")。
此函数依赖于系统,并且并非在所有平台上都可用。
io.read({...}) io.read()
等效于 io.input():read
io.tmpfile() io.tmpfile()
返回一个临时文件的句柄。此文件以更新模式打开,并在程序结束时自动删除。
io.type({obj}) io.type()
检查 {obj} 是否是一个有效的文件句柄。如果 {obj} 是一个打开的文件句柄,则返回字符串 "file",如果 {obj} 是一个关闭的文件句柄,则返回 "closed file",如果 {obj} 不是文件句柄,则返回 nil
io.write({...}) io.write()
等效于 io.output():write
file:close() file:close()
关闭 file。请注意,当文件句柄被垃圾回收时,文件会自动关闭,但这需要不可预测的时间才能发生。
file:flush() file:flush()
将任何写入的数据保存到 file
file:lines() file:lines()
返回一个 迭代器 函数,每次调用它,都会从文件返回一个新的行。因此,构造
for line in file:lines() do body end
将遍历文件的所有行。(与 io.lines 不同,此函数在循环结束时不会关闭文件。)
file:read({...}) file:read()
根据给定的格式读取文件 file,这些格式指定要读取的内容。对于每个格式,函数返回一个包含读取字符的字符串(或数字),或者在无法按指定格式读取数据时返回 nil。当不带格式调用时,它使用默认格式读取整个下一行(见下文)。
可用的格式有
"*n" 读取一个数字;这是唯一返回数字而不是字符串的格式。 "*a" 读取整个文件,从当前位置开始。在文件结束时,它返回空字符串。 "*l" 读取下一行(跳过行尾),在文件结束时返回 nil。这是默认格式。 number 读取最多指定数量的字符的字符串,在文件结束时返回 nil。如果 number 为零,则不读取任何内容并返回空字符串,或者在文件结束时返回 nil
file:seek([{whence}] [, {offset}]) file:seek()
设置和获取文件位置,从文件开头测量,到由 {offset} 加上由字符串 {whence} 指定的基准位置,如下所示
"set": 基准为位置 0(文件开头);
"cur": 基准为当前位置;
"end": 基准为文件结尾;
如果成功,函数 seek 返回最终文件位置,以从文件开头测量的字节为单位。如果此函数失败,它将返回 nil,以及一个描述错误的字符串。
{whence} 的默认值为 "cur"{offset} 的默认值为 0。因此,调用 file:seek() 返回当前文件位置,而不改变它;调用 file:seek("set") 将位置设置为文件开头(并返回 0);调用 file:seek("end") 将位置设置为文件结尾,并返回其大小。
file:setvbuf({mode} [, {size}]) file:setvbuf()
设置输出文件的缓冲模式。有三种可用模式
"no" 无缓冲;任何输出操作的结果都会立即出现。 "full" 全缓冲;输出操作仅在缓冲区已满时执行(或显式地 flush 文件时(参见 io.flush())。 "line" 行缓冲;输出被缓冲,直到输出一个换行符,或者有一些特殊文件(如终端设备)的输入。
对于最后两种情况,{size} 指定缓冲区的大小,以字节为单位。默认值为合适的大小。
file:write({...}) file:write()
将每个参数的值写入 file。参数必须是字符串或数字。要写入其他值,请使用 tostring tostring()string.format string.format()write 之前。

5.8 操作系统功能 lua-lib-os

这个库是通过表 os 实现的。
os.clock() os.clock()
返回程序使用的 CPU 时间(以秒为单位)的近似值。
os.date([{format} [, {time}]]) os.date()
返回一个字符串或一个包含日期和时间的表,根据给定的字符串 {format} 格式化。
如果 {time} 参数存在,则这是要格式化的时间(有关此值的描述,请参见 os.time 函数 os.time())。否则,date 将格式化当前时间。
如果 {format}! 开头,则日期以协调世界时格式化。在这个可选字符之后,如果 {format} 是字符串 "*t",则 date 返回一个包含以下字段的表:year(四位数字)、month(1-12)、day(1-31)、hour(0-23)、min(0-59)、sec(0-61)、wday(星期几,星期日为 1)、yday(一年中的第几天)和 isdst(夏令时标志,布尔值)。
如果 {format} 不是 "*t",则 date 返回日期作为字符串,根据与 C 函数 strftime 相同的规则格式化。
当不带参数调用时,date 返回一个合理的日期和时间表示,它取决于主机系统和当前区域设置(即,os.date() 等效于 os.date("%c"))。
os.difftime({t2}, {t1}) os.difftime()
返回从时间 {t1} 到时间 {t2} 的秒数。在 POSIX、Windows 和一些其他系统中,此值正好是 t2 - t1
os.execute([{command}]) os.execute()
此函数等效于 C 函数 system。它将 {command} 传递给操作系统 shell 执行。它返回一个状态码,该状态码是系统相关的。如果 {command} 缺失,则如果 shell 可用,则返回非零值,否则返回零。
os.exit([{code}]) os.exit()
调用 C 函数 exit,并带有一个可选的 {code},以终止主机程序。{code} 的默认值为成功代码。
os.getenv({varname}) os.getenv()
返回进程环境变量 {varname} 的值,或者如果变量未定义,则返回 nil
os.remove({filename}) os.remove()
删除具有给定名称的文件。目录必须为空才能删除。如果此函数失败,它将返回 nil,以及一个描述错误的字符串。
os.rename({oldname}, {newname}) os.rename()
将名为 {oldname} 的文件重命名为 {newname}。如果此函数失败,它将返回 nil,以及一个描述错误的字符串。
os.setlocale({locale} [, {category}]) os.setlocale()
设置程序的当前区域设置。{locale} 是一个指定区域设置的字符串;{category} 是一个可选的字符串,描述要更改的类别:"all""collate""ctype""monetary""numeric""time";默认类别为 "all"。函数返回新区域设置的名称,或者如果请求无法满足,则返回 nil
os.time([{table}]) os.time()
在不带参数调用时返回当前时间,或者返回一个表示由给定表指定的日期和时间的数字。此表必须具有字段 yearmonthday,并且可能具有字段 hourminsecisdst(有关这些字段的描述,请参见 os.date 函数 os.date())。
返回值是一个数字,其含义取决于您的系统。在 POSIX、Windows 和一些其他系统中,此数字计算自某个给定开始时间(“纪元”)以来的秒数。在其他系统中,含义未指定,time 返回的数字只能用作 datedifftime 的参数。
os.tmpname() os.tmpname()
返回一个包含可用于临时文件的字符串的字符串。必须在使用前显式打开该文件,并在不再需要时显式删除它。

5.9 调试库 lua-lib-debug

此库提供了 Lua 程序的调试接口功能。在使用此库时,您应该格外小心。此处提供的函数应仅用于调试和类似任务,例如性能分析。请抵制将它们用作常规编程工具的诱惑:它们可能非常慢。此外,它的几个函数违反了有关 Lua 代码的一些假设(例如,函数的局部变量无法从外部访问,或者 Lua 代码无法更改用户数据元表),因此可能损害其他安全的代码。
此库中的所有函数都在 debug 表中提供。所有对线程进行操作的函数都有一个可选的第一个参数,即要操作的线程。默认值始终是当前线程。
debug.debug() debug.debug()
进入与用户的交互模式,运行用户输入的每个字符串。使用简单的命令和其他调试工具,用户可以检查全局变量和局部变量、更改其值、评估表达式等。仅包含单词 cont 的一行将完成此函数,以便调用者继续执行。
请注意,debug.debug 的命令不会在任何函数中词法嵌套,因此无法直接访问局部变量。
debug.getfenv(o) debug.getfenv()
返回对象 {o} 的环境。
debug.gethook([{thread}]) debug.gethook()
返回线程的当前挂钩设置,作为三个值:当前挂钩函数、当前挂钩掩码和当前挂钩计数(由 debug.sethook 函数设置)。
debug.getinfo([{thread},] {function} [, {what}]) debug.getinfo()
返回一个包含有关函数的信息的表。您可以直接给出函数,也可以将数字作为 {function} 的值给出,这意味着在给定线程的调用栈的 {function} 级运行的函数:级别 0 是当前函数(getinfo 本身);级别 1 是调用 getinfo 的函数;等等。如果 {function} 是一个大于活动函数数量的数字,则 getinfo 返回 nil
返回的表可能包含由 lua_getinfo 返回的所有字段(参见 lua_getinfo()),字符串 {what} 描述要填充的字段。{what} 的默认值为获取所有可用信息,除了有效行的表。如果存在,选项 f 将添加一个名为 func 的字段,其中包含函数本身。如果存在,选项 L 将添加一个名为 activelines 的字段,其中包含有效行的表。
例如,表达式 debug.getinfo(1,"n").name 返回当前函数的名称(如果可以找到合理的名称),并且 debug.getinfo(print) 返回一个包含有关 print 函数的所有可用信息的表。
debug.getlocal([{thread},] {level}, {local}) debug.getlocal()
此函数返回堆栈第 {level} 层函数中索引为 {local} 的局部变量的名称和值。(第一个参数或局部变量的索引为 1,依此类推,直到最后一个活动的局部变量。) 如果没有给定索引的局部变量,则该函数返回 nil,当使用超出范围的 {level} 调用时,该函数会引发错误。(您可以调用 debug.getinfo debug.getinfo() 来检查级别是否有效。)
((左括号)开头的变量名称代表内部变量(循环控制变量、临时变量和 C 函数局部变量)。
debug.getmetatable({object}) debug.getmetatable()
返回给定 {object} 的元表,如果它没有元表,则返回 nil
debug.getregistry() debug.getregistry()
返回注册表 (参见 lua-registry)。
debug.getupvalue({func}, {up}) debug.getupvalue()
此函数返回函数 {func} 中索引为 {up} 的闭包变量的名称和值。如果不存在给定索引的闭包变量,该函数返回 nil
debug.setfenv({object}, {table}) debug.setfenv()
将给定 {object} 的环境设置为给定的 {table}。返回 {object}
debug.sethook([{thread},] {hook}, {mask} [, {count}]) debug.sethook()
将给定函数设置为钩子。字符串 {mask} 和数字 {count} 描述了何时调用钩子。字符串掩码可以包含以下字符,具有以下含义
"c" : 每当 Lua 调用函数时,都会调用钩子;
"r" : 每当 Lua 从函数返回时,都会调用钩子;
"l" : 每当 Lua 进入新代码行时,都会调用钩子。
{count} 非零时,在每 {count} 条指令后调用钩子。
当没有参数调用时,debug.sethook 会关闭钩子。
当调用钩子时,它的第一个参数是一个字符串,描述了触发其调用的事件:"call""return"(或“tail return”)、"line""count"。对于行事件,钩子也会得到新的行号作为其第二个参数。在钩子内部,您可以调用 getinfo,级别为 2,以获取有关正在运行函数的更多信息(级别 0 是 getinfo 函数,级别 1 是钩子函数),除非事件是 "tail return"。在这种情况下,Lua 只是模拟了返回,调用 getinfo 将返回无效数据。
debug.setlocal([{thread},] {level}, {local}, {value}) debug.setlocal()
此函数将值 {value} 赋给堆栈第 {level} 层函数中索引为 {local} 的局部变量。如果不存在给定索引的局部变量,则该函数返回 nil,当使用超出范围的 {level} 调用时,该函数会引发错误。(您可以调用 getinfo 来检查级别是否有效。) 否则,它将返回局部变量的名称。
debug.setmetatable({object}, {table}) debug.setmetatable()
将给定 {object} 的元表设置为给定的 {table}(可以是 nil)。
debug.setupvalue({func}, {up}, {value}) debug.setupvalue()
此函数将值 {value} 赋给函数 {func} 中索引为 {up} 的闭包变量。如果不存在给定索引的闭包变量,该函数返回 nil。否则,它将返回闭包变量的名称。
debug.traceback([{thread},] [{message} [,{level}]]) debug.traceback()
返回一个包含调用堆栈回溯的字符串。一个可选的 {message} 字符串将附加到回溯的开头。一个可选的 {level} 数字告诉从哪个级别开始回溯(默认值为 1,即调用 traceback 的函数)。

参考文献 lua-ref-bibliography

此帮助文件是对以下主要参考资料的略微改编
R. Ierusalimschy, L. H. de Figueiredo 和 W. Celes.,“Lua: 5.1 参考手册”,https://lua.ac.cn/manual/5.1/manual.html
以下参考资料讨论了 Lua
R. Ierusalimschy, L. H. de Figueiredo 和 W. Celes.,“Lua --- 一种可扩展的扩展语言”。“软件:实践与经验”第 26 卷,第 6 期(1996 年)635-652。
L. H. de Figueiredo, R. Ierusalimschy 和 W. Celes.,“扩展应用程序的语言设计与实现”。“第二十一届巴西软件与硬件研讨会论文集”(1994 年)273-283。
L. H. de Figueiredo, R. Ierusalimschy 和 W. Celes.,“Lua:一种可扩展的嵌入式语言”。“Dr. Dobb's Journal”第 21 卷,第 12 期(1996 年 12 月)26-33。
R. Ierusalimschy, L. H. de Figueiredo 和 W. Celes.,“一种扩展语言的演变:Lua 的历史”。“第五届巴西编程语言研讨会论文集”(2001 年)B-14-B-28。
此帮助文件与 Lua 5.1 及 Lua 5.1 手册具有相同的版权和许可
版权所有 (c) 1994-2006 Lua.org,PUC-Rio。
特此免费授予任何获得本软件和相关文档文件(“软件”)副本的人以任何目的不受限制地处理软件的权利,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件的副本,以及允许获得软件的人这样做,但须遵守以下条件
以上版权声明和本许可声明应包含在本软件的所有副本或大部分内容中。
软件按“现状”提供,没有任何明示或暗示的保证,包括但不限于适销性、特定目的的适用性和非侵权保证。在任何情况下,作者或版权持有人均不对因使用或无法使用本软件而引起的任何索赔、损害或其他责任承担责任,无论是在合同、侵权或其他情况下产生的,即使已告知此类损害的可能性。

Lua 文档 lua-ref-doc

这是一个 Vim 帮助文件,包含 Lua 5.1 的参考,并且它(除了一些例外和调整之外)是 Lua 5.1 参考手册的副本(参见 lua-ref-bibliography)。有关使用方法的信息,请参阅 lua-ref-doc。有关版权信息,请参见 lua-ref-copyright
实现此参考的主要思路和概念来自 Christian Habermann 的 CRefVim 项目 (https://www.vim.org/scripts/script.php?script_id=614)。
适用于捆绑的 Nvim 文档;原始插件可以在 https://www.vim.org/scripts/script.php?script_id=1291 找到
命令索引
快速参考