Lua 5.3 参考手册--翻译

1 – Introduction

Lua是一种强大、高效、轻量级、可嵌入的脚本语言。它支持过程编程、面向对象编程、函数编程、数据驱动编程和数据描述。

Lua结合了简单的过程语法和基于关联数组和可扩展语义的强大数据描述结构。Lua是动态类型的,通过使用基于寄存器的虚拟机解释字节码来运行,并且具有带增量垃圾收集的自动内存管理,使其成为配置、脚本和快速原型的理想选择。

LUA被实现为一个库,它是在C语言中编写的,它是标准C和C++的公共子集。Lua发行版包括一个名为Lua的宿主程序,它使用Lua库提供一个完整的、独立的Lua解释器,供交互或批处理使用。Lua既可用作任何需要的程序的强大、轻量级、可嵌入的脚本语言,也可用作强大、轻量级和高效的独立语言。

作为一种扩展语言,Lua没有“主”程序的概念:它嵌入在一个宿主客户机(称为嵌入程序)中,或者仅仅是宿主。(通常,这个主机是独立的lua程序。)主机程序可以调用函数来执行一段lua代码,可以编写和读取lua变量,并且可以注册C函数来被lua代码调用。通过使用C函数,Lua可以被扩充以处理各种不同的领域,从而创建共享语法框架的定制编程语言。

Lua是免费软件,按照其许可证的规定,它通常不提供任何保证。本手册中描述的实现可以在Lua的官方网站www.Lua.org上找到。

与其他参考手册一样,本文件在某些地方是干燥的。有关Lua设计背后决策的讨论,请参阅Lua网站上提供的技术论文。有关Lua中编程的详细介绍,请参阅Roberto的书《Lua中的编程》。

2 – 基本概念

本节介绍语言的基本概念。

2.1 – 值和类型

Lua是一种动态类型语言。这意味着变量没有类型;只有值才有类型。语言中没有类型定义。所有的价值观都有自己的类型。

Lua中的所有值都是一级值。这意味着所有值都可以存储在变量中,作为参数传递给其他函数,并作为结果返回。

Lua中有八种基本类型:nil、boolean、number、string、function、userdata、thread和table。nil类型只有一个值nil,其主要属性与任何其他值都不同;它通常表示缺少有用的值。类型boolean有两个值,false和true。nil和false都使条件为false;任何其他值都使条件为true。类型号表示整数和实数(浮点数)。类型字符串表示不可变的字节序列。Lua是8位干净的:字符串可以包含任何8位值,包括嵌入的零(’\0’)。Lua也是不可知编码的;它对字符串的内容没有任何假设。

类型号使用两个内部表示或两个子类型,一个称为整数,另一个称为浮点。Lua对每个表示的使用时间有明确的规则,但它也会根据需要在它们之间自动转换(见第3.4.3节)。因此,程序员可以选择忽略整数和浮点数之间的差异,或者假设完全控制每个数字的表示。标准Lua使用64位整数和双精度(64位)浮点,但也可以编译Lua,使其使用32位整数和/或单精度(32位)浮点。对于小型机器和嵌入式系统来说,整数和浮点数都是32位的选项特别有吸引力。(请参见文件luaconf.h中的宏LUA_32位。)

Lua可以调用(和操作)用Lua编写的函数和用C编写的函数(参见第3.4.10节)。两者都由type函数表示。

提供userdata类型是为了允许在Lua变量中存储任意C数据。userdata值表示原始内存块。有两种类型的用户数据:full userdata(由Lua管理的内存块的对象)和light userdata(只是一个C指针值)。Userdata在Lua中没有预定义的操作,除了赋值和标识测试。通过使用元表,程序员可以定义完整用户数据值的操作(见2.4节)。不能在Lua中创建或修改Userdata值,只能通过C API。这保证了宿主程序拥有的数据的完整性。

类型线程表示执行的独立线程,用于实现协同程序(参见第2.6节)。Lua线程与操作系统线程无关。Lua支持所有系统上的协程,甚至那些不支持本机线程的系统。

类型表实现关联数组,也就是说,数组不仅可以作为数字的索引,还可以作为除nil和NaN之外的任何Lua值的索引。(数字不是用来表示未定义或不可表示的数值结果的特殊值,例如0/0。)表可以是异构的;也就是说,它们可以包含所有类型的值(nil除外)。值为nil的任何键都不被视为表的一部分。相反,任何不属于表的键都有一个关联值nil。

表是Lua中唯一的数据结构机制;它们可用于表示普通数组、列表、符号表、集合、记录、图形、树等。Lua使用字段名作为索引来表示记录。语言通过提供一个.name作为[“name”]的语法糖来支持这种表示。在Lua中创建表格有几种方便的方法(见第3.4.9节)。

与索引一样,表字段的值可以是任何类型。特别是,因为函数是一级值,所以表字段可以包含函数。因此,表格也可以携带方法(见第3.4.11节)。

表的索引遵循语言中原始等式的定义。表达式a[i]和a[j]表示相同的表元素,前提是且仅当i和j原始相等(即,没有元方法时相等)。特别是,具有整数值的浮点等于它们各自的整数(例如,1.0==1)。为了避免含糊不清,使用整数值作为键的任何浮点都将转换为其各自的整数。例如,如果您编写一个[2.0]=true,则插入表中的实际键将是整数2。(另一方面,2和“2”是不同的Lua值,因此表示不同的表条目。)

表、函数、线程和(完整的)userdata值是对象:变量实际上不包含这些值,只包含对它们的引用。赋值、参数传递和函数返回总是操作对这些值的引用;这些操作并不意味着任何类型的复制。

库函数类型返回一个字符串,描述给定值的类型(见6.1节)。

2.2–环境和全局环境

如第3.2节和第3.3.3节所述,对自由名称(即不绑定到任何声明的名称)var的任何引用在语法上都被翻译为_ENV.var。此外,每个块都在名为_ENV的外部局部变量(见第3.3.2节)的范围内编译,因此_ENV本身永远不是块中的自由名称。

尽管存在这个外部_ENV变量和自由名称的转换,但_ENV是一个完全规则的名称。特别是,您可以使用该名称定义新变量和参数。每个对自由名称的引用都使用程序中该点可见的环境,遵循Lua的常见可见性规则(见第3.5节)。

任何用作“ENV”值的表都称为环境。

Lua保持了一个被称为全球环境的独特环境。该值保存在C注册表中的特殊索引中(见第4.5节)。在Lua中,全局变量用相同的值初始化。(G从不在内部使用。)

当Lua加载块时,其环境upvalue的默认值是全局环境(请参见加载)。因此,默认情况下,Lua代码中的自由名称指的是全局环境中的条目(因此,它们也被称为全局变量)。此外,所有标准库都加载在全局环境中,其中的一些函数在该环境中运行。可以使用load(或loadfile)加载具有不同环境的块。(在C中,必须加载块,然后更改其第一个upvalue的值。)

2.3 – 错误处理

如第3.2节和第3.3.3节所述,对自由名称(即不绑定到任何声明的名称)var的任何引用在语法上都被翻译为_ENV.var。此外,每个块都在名为_ENV的外部局部变量(见第3.3.2节)的范围内编译,因此_ENV本身永远不是块中的自由名称。

尽管存在这个外部_ENV变量和自由名称的转换,但_ENV是一个完全规则的名称。特别是,您可以使用该名称定义新变量和参数。每个对自由名称的引用都使用程序中该点可见的环境,遵循Lua的常见可见性规则(见第3.5节)。

任何用作“ENV”值的表都称为环境。

Lua保持了一个被称为全球环境的独特环境。该值保存在C注册表中的特殊索引中(见第4.5节)。在Lua中,全局变量用相同的值初始化。(G从不在内部使用。)

当Lua加载块时,其环境upvalue的默认值是全局环境(请参见加载)。因此,默认情况下,Lua代码中的自由名称指的是全局环境中的条目(因此,它们也被称为全局变量)。此外,所有标准库都加载在全局环境中,其中的一些函数在该环境中运行。可以使用load(或loadfile)加载具有不同环境的块。(在C中,必须加载块,然后更改其第一个upvalue的值。)

2.4 – 元表和元方法

Lua中的每个值都可以有一个元表。这个元表是一个普通的Lua表,它定义了在某些特殊操作下原始值的行为。通过在值的元表中设置特定字段,可以更改该值上操作行为的几个方面。例如,当一个非数字值是加法的操作数时,Lua会在该值的元表的字段“\u add”中检查函数。如果找到一个,Lua调用这个函数来执行加法。

元表中每个事件的键是以两个下划线为前缀的事件名字符串;相应的值称为元方法。在上一个例子中,键是“\uu add”,元方法是执行加法的函数。除非另有说明,元方法应为函数值。

您可以使用getmetatable函数查询任何值的元表。Lua使用原始访问来查询元表中的元方法(请参见rawget)。因此,要在对象o中检索事件ev的元方法,Lua执行与以下代码等效的操作:

 rawget(getmetatable(o) or {}, "__ev")

可以使用setmetatable函数替换表的元表。不能从Lua代码更改其他类型的元表(使用调试库(§6.10))除外;应该使用C API。

表和完整的userdata有单独的元表(尽管多个表和userdata可以共享它们的元表)。所有其他类型的值在每种类型中共享一个元表;也就是说,对于所有数字有一个元表,对于所有字符串有一个元表,等等。默认情况下,一个值没有元表,但是字符串库为字符串类型设置一个元表(见6.4节)。

元表控制对象在算术操作、按位操作、顺序比较、连接、长度操作、调用和索引中的行为。元表还可以定义在垃圾收集用户数据或表时要调用的函数(§2.5)。

对于一元运算符(求反、length和按位NOT),计算并调用metamethod时使用与第一个操作数相等的伪第二个操作数。这个额外的操作数只是为了简化Lua的内部结构(通过使这些操作符的行为类似于二进制操作),并且可能在将来的版本中被删除。(在大多数情况下,这个额外的操作数是不相关的。)

接下来给出了由元表控制的事件的详细列表。每个操作都由相应的键标识。

__add:加法操作。如果加法的任何操作数不是数字(也不是可强制为数字的字符串),Lua将尝试调用元方法。首先,Lua将检查第一个操作数(即使它是有效的)。如果该操作数没有为“加法”定义元方法,则Lua将检查第二个操作数。如果Lua可以找到一个元方法,那么它将使用两个操作数作为参数来调用元方法,并且调用的结果(调整为一个值)是操作的结果。否则,将引发错误。
__sub: 减法运算。类似于加法运算的行为。
__mul: 乘法运算。类似于加法运算的行为。
__div: 除法运算。类似于加法运算的行为。
__mod: 取模运算。类似于加法运算的行为。
__pow: 指数运算。类似于加法运算的行为。
__unm: 取反(一元)运算。类似于加法运算的行为。
__idiv: 楼层分割(//)操作。类似于加法运算的行为。
__band: 按位与(&)操作。与加法操作类似的行为,但如果任何操作数既不是整数也不是可强制为整数的值,则Lua将尝试使用元方法(请参阅第3.4.3节)。
__bor: 按位或(|)运算。类似于按位与运算的行为。
__bxor: 按位异或(二进制~)操作。类似于按位与运算的行为。
__bnot: 按位非(一元~)操作。类似于按位与运算的行为。
__shl: 按位左移(<<)操作。类似于按位与运算的行为。
__shr: 按位右移(>>)操作。类似于按位与运算的行为。
__concat: 连接(..)操作。与加法操作类似的行为,但如果任何操作数既不是字符串也不是数字(总是可强制为字符串),Lua将尝试使用元方法。
__len: 长度(#)操作。如果对象不是字符串,Lua将尝试其元方法。如果有一个元方法,Lua用对象作为参数调用它,调用的结果(总是调整为一个值)就是操作的结果。如果没有元方法,但对象是一个表,那么Lua使用表长度操作(参见第3.4.7节)。否则,Lua会引发错误。
__eq: 相等(==)操作。类似于加法操作的行为,除了Lua只在被比较的值同时是两个表或两个完整的userdata并且它们不是基本相等时才会尝试metamethod。调用的结果始终转换为布尔值。
__lt: 小于(<)操作。类似于加法操作的行为,除了Lua只在比较的值既不是数字也不是字符串时才尝试元方法。调用的结果始终转换为布尔值。
__le: 小于等于(<=)的操作。与其他操作不同,不相等的操作可以使用两个不同的事件。首先,Lua在两个操作数中查找元方法,就像在小于操作中一样。如果它找不到这样的元方法,那么它将尝试使用u lt元方法,假设a<=b等于not(b

在将表设置为某个对象的元表之前,将所有需要的元方法添加到表中是一个好的实践。尤其是,gc元方法仅在遵循此顺序时有效(见第2.5.1节)。

因为元表是常规表,所以它们可以包含任意字段,而不仅仅是上面定义的事件名。标准库中的某些函数(例如tostring)将元表中的其他字段用于自己的目的。

2.5 – 垃圾回收

Lua执行自动内存管理。这意味着您不必担心为新对象分配内存或在不再需要对象时释放内存。Lua通过运行垃圾收集器来自动管理内存,以收集所有死的对象(即Lua无法再访问的对象)。Lua使用的所有内存都受到自动管理:字符串、表、用户数据、函数、线程、内部结构等。

Lua实现了一个增量标记和扫描收集器。它使用两个数字来控制垃圾回收周期:垃圾回收器暂停和垃圾回收器步骤乘数。两者都使用百分比作为单位(例如,值100表示内部值1)。

垃圾收集器暂停控制收集器在开始新循环之前等待的时间。值越大,收集器的攻击性就越小。小于100的值表示收集器不会等待开始新的循环。值200表示收集器在开始新周期之前等待使用的总内存翻倍。

垃圾收集器步骤乘数控制收集器相对于内存分配的相对速度。较大的值使收集器更具攻击性,但也会增加每个增量步骤的大小。不应使用小于100的值,因为这些值会使收集器太慢,并且可能导致收集器永远无法完成循环。默认值是200,这意味着收集器的运行速度是内存分配速度的“两倍”。

如果将阶跃乘数设置为非常大的数字(大于程序可能使用的最大字节数的10%),则收集器的行为类似于stop the world收集器。如果将pause设置为200,则收集器的行为与旧Lua版本相同,每次Lua加倍其内存使用量时都会执行完整的收集。

您可以通过调用C中的lua_gc或lua中的collectgarbage来更改这些号码。您还可以使用这些功能直接控制收集器(例如,停止并重新启动它)。

2.5.1–垃圾回收元方法

您可以为表设置垃圾收集器元方法,并使用C API为完整的用户数据设置垃圾收集器元方法(请参阅第2.4节)。这些元方法也称为终结器。终结器允许您协调Lua的垃圾收集和外部资源管理(例如关闭文件、网络或数据库连接,或释放自己的内存)。

要使对象(表或用户数据)在收集时完成,必须将其标记为完成。当您设置了一个对象的元表并且该元表有一个由字符串“\uu gc”索引的字段时,您可以标记该对象以进行终结。请注意,如果设置了一个不带gc字段的元表,然后在元表中创建该字段,则不会标记该对象以进行终结。

当标记的对象成为垃圾时,垃圾收集器不会立即收集它。相反,Lua把它放在一个列表中。在收集完之后,Lua会查看这个列表。对于列表中的每个对象,它都会检查对象的gc元方法:如果它是函数,Lua会使用该对象作为其单个参数调用它;如果元方法不是函数,Lua只会忽略它。

在每个垃圾收集周期结束时,对象的终结器将按对象在该周期中收集的对象中被标记为终结的相反顺序调用;也就是说,要调用的第一个终结器是与程序中最后标记的对象关联的终结器。在执行常规代码的过程中,每个终结器的执行可能在任何时候发生。

因为要收集的对象仍然必须由终结器使用,所以该对象(以及只能通过它访问的其他对象)必须由Lua恢复。通常,这种复活是暂时的,对象内存在下一个垃圾收集周期中被释放。但是,如果终结器将对象存储在某个全局位置(例如,全局变量),则复活是永久的。此外,如果终结器将终结对象标记为再次进行终结,则在下一个无法访问该对象的周期中,将再次调用其终结器。在任何情况下,对象内存仅在无法访问对象且未标记为完成的GC周期中释放。

当您关闭一个状态(请参阅lua_close)时,lua会调用所有标记为要完成的对象的终结器,其顺序与标记的顺序相反。如果终结器在该阶段标记要收集的对象,则这些标记无效。

2.5.2–弱表

弱表是元素是弱引用的表。垃圾收集器忽略弱引用。换句话说,如果对对象的唯一引用是弱引用,那么垃圾收集器将收集该对象。

弱表可以有弱键、弱值或两者都有。具有弱值的表允许收集其值,但阻止收集其键。同时具有弱键和弱值的表允许同时收集键和值。在任何情况下,如果收集了键或值,则从表中删除整个对。表的弱点由它的元表的“模式”字段控制。如果“模式”字段是包含字符“k”的字符串,则表中的键是弱键。如果模式包含“v”,则表中的值很弱。

具有弱键和强值的表也称为ephemeron表。在ephemeron表中,只有当一个值的键是可到达的时,它才被认为是可到达的。特别是,如果对键的唯一引用是通过其值来实现的,则将删除该对。

只有在下一个收集周期中,表的弱点的任何更改才会生效。特别是,如果您将弱点更改为更强的模式,Lua仍然可以在更改生效之前从该表中收集一些项。

只有具有显式构造的对象才会从弱表中删除。数值(如数字和light C函数)不受垃圾收集的影响,因此不会从弱表中删除(除非收集了它们的关联值)。尽管字符串要进行垃圾收集,但它们没有显式构造,因此不会从弱表中删除。

复活的对象(即正在定稿的对象和只能通过定稿的对象访问的对象)在弱表中具有特殊的行为。它们在运行终结器之前从弱值中移除,但仅在运行终结器之后的下一个集合中从弱键中移除,此时此类对象实际上已被释放。此行为允许终结器通过弱表访问与对象关联的属性。

如果弱表在收集周期中的复活对象中,则在下一个周期之前可能无法正确清除该表。

2.6-联程

Lua支持协同路由,也称为协作多线程。Lua中的协程表示一个独立的执行线程。然而,与多线程系统中的线程不同,协程只通过显式调用yield函数来暂停其执行。

您可以通过调用coroutine.create来创建协程。它唯一的参数是一个函数,它是协程的主要函数。create函数只创建一个新的协程并返回一个句柄(thread类型的对象);它不启动协程。

您可以通过调用coroutine.resume来执行协程。第一次调用coroutine.resume时,将coroutine.create返回的线程作为其第一个参数传递给coroutine.resume,则coroutine通过调用其主函数开始执行。传递给coroutine.resume的额外参数将作为参数传递给该函数。在协同程序开始运行之后,它一直运行到终止或退出。

协程可以通过两种方式终止其执行:正常情况下,当其主函数返回时(显式或隐式地,在最后一条指令之后);异常情况下,如果存在未受保护的错误。在正常终止的情况下,coroutine.resume返回true,加上coroutine主函数返回的任何值。如果出现错误,coroutine.resume将返回false和一个错误对象。

一个协程通过调用coroutine.yield来产生。当一个协程产生时,对应的coroutine.resume立即返回,即使该产生发生在嵌套函数调用中(即,不是在主函数中,而是在主函数直接或间接调用的函数中)。对于yield,coroutine.resume还返回true,加上传递给coroutine.yield的任何值。下一次恢复同一协程时,它将从产生的点继续执行,调用coroutine.yield将返回传递给coroutine.resume的任何额外参数。

与coroutine.create类似,coroutine.wrap函数也创建了一个协程,但它返回的函数不是协程本身,而是在调用时恢复协程的函数。传递给此函数的任何参数都将作为额外参数传递给coroutine.resume。wrap返回coroutine.resume返回的所有值,第一个值除外(布尔错误代码)。与coroutine.resume不同,coroutine.wrap不捕获错误;任何错误都会传播到调用方。

作为协作工作方式的示例,请参考以下代码:

     function foo (a)
       print("foo", a)
       return coroutine.yield(2*a)
     end
     
     co = coroutine.create(function (a,b)
           print("co-body", a, b)
           local r = foo(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

还可以通过C API创建和操作协同程序:请参见函数lua_newthread、lua_resume和lua_yield。

3 – 语法

本节描述Lua的词汇、语法和语义。换句话说,本节描述哪些令牌是有效的、如何组合它们以及它们的组合意味着什么。

语言结构将使用常用的扩展BNF表示法进行解释,其中{a}表示0或更多a,[a]表示可选a。非终端显示为非终端,关键字显示为kword,其他终端符号显示为’=’。Lua的完整语法见本手册末尾的第9节。

3.1–词汇惯例

Lua是一种自由形式的语言。它忽略词法元素(标记)之间的空格(包括新行)和注释,名称和关键字之间的分隔符除外。

Lua中的名称(也称为标识符)可以是任何字母、数字和下划线字符串,不能以数字开头,也不能是保留字。标识符用于命名变量、表字段和标签。

以下关键字是保留关键字,不能用作名称:

    and       break     do        else      elseif    end
     false     for       function  goto      if        in
     local     nil       not       or        repeat    return
     then      true      until     while

Lua是区分大小写的语言:它是一个保留字,但是和和是两个不同的有效名称。作为惯例,程序应避免创建以下划线开头、后跟一个或多个大写字母的名称(例如_VERSION)。

以下字符串表示其他标记:

   +     -     *     /     %     ^     #
     &     ~     |     <<    >>    //
     ==    ~=    <=    >=    <     >     =
     (     )     {     }     [     ]     ::
     ;     :     ,     .     ..    ...

短文本字符串可以通过匹配单引号或双引号来分隔,并且可以包含以下类似于C的转义序列:’\A’(bell)、’\b’(backspace)、’\f’(form feed)、’\n’(newline)、’\r’(回车符)、’\t’(水平制表符)、’\v’(垂直制表符)、’’(反斜杠)、’’(引号[双引号])和’’(撇号[单引号引用)。反斜杠后跟换行符将在字符串中生成换行符。转义序列’\z’跳过以下空白字符范围,包括换行符;在不将换行符和空格添加到字符串内容的情况下,将长文本字符串打断并缩进多行特别有用。短文本字符串不能包含未转换的换行符,也不能包含未形成有效转义序列的转义符。

我们可以通过数字值(包括嵌入的零)指定短文本字符串中的任何字节。这可以通过转义序列xXX(其中XX是正好两个十六进制数字的序列)或转义序列ddd(其中ddd是最多三个十进制数字的序列)完成。(请注意,如果十进制转义序列后面跟着一个数字,则必须使用正好三个数字来表示。)

Unicode字符的UTF-8编码可以插入到具有转义序列u{XXX}(注意必须包含括号)的文本字符串中,其中XXX是表示字符代码点的一个或多个十六进制数字的序列。

文字字符串也可以使用长括号括起的长格式定义。我们定义了一个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以文本模式打开文件进行解析,系统文件函数可能有一些控制字符的问题。因此,将非文本数据表示为带引号的文本,并对非文本字符使用显式转义序列更安全。

数字常量(或数字)可以用可选的小数部分和可选的十进制指数写入,用字母“e”或“e”标记。Lua还接受以x或x开头的十六进制常量。十六进制常量还接受可选的小数部分加上可选的二进制指数(用字母“p”或“p”标记)。带有基点或指数的数字常量表示浮点;否则,如果其值适合整数,则表示整数。有效整数常量的示例如下

  3   345   0xff   0xBEBADA

有效浮点常量的示例如下

 3.0     3.1416     314.16e-2     0.31416E1     34e1
     0x0.1E  0xA23p-4   0X1.921FB54442D18P+1

注释以字符串外部任意位置的双连字符(–)开头。如果紧跟在–后面的文本不是开首的长括号,则注释是一个短注释,它将一直运行到行的末尾。否则,它是一个长注释,将一直运行到相应的右长括号。长注释通常用于暂时禁用代码。

3.2 – Variables

你可能感兴趣的:(Lua 5.3 参考手册--翻译)