Lua 五二

lua-users home
wiki

Lua 5.2 是继 5.1 之后 Lua 的最新主要版本[1]。此页面包含一些在 alpha/beta 测试期间邮件列表中的信息,这些信息可能已过时或不正确。有关 Lua 5.2 的官方信息和下载,请访问 [www.lua.org/manual/5.2]。

范围

虽然 5.1.x 版本严格来说只是 5.1 的 bug 修复版本[12][13][2],但 Lua 5.2 允许进行破坏完全兼容性的设计更改。

历史

背景信息

注意

请随时更新参考资料! (以及此处的所有其他内容。) -- AlexanderGladysh

待办事项:以下某些部分可能需要更新以反映最终的 Lua 5.2.0 版本。

紧急垃圾收集器

Lua 核心在分配失败时强制执行 GC。

参考资料

分代垃圾收集器(可选且实验性)

短暂表

只有当键可访问时,具有弱键的表才会访问值。

参考资料

具有终结器的用户数据

具有终结器的用户数据在 GC 的一个单独列表中保留。

参考资料

非字符串错误消息

Lua 解释器更好地处理非字符串错误消息。

参考资料

xpcall() 改进

xpcall() 现在接受回调的 arguments,就像 pcall() 一样

参考资料

package.searchpath()

新函数 package.searchpath() 用于搜索您的文件,就像 require() 一样。

参考资料

package.config

现在记录了在 package.config 中可用的编译时模块系统设置。

参考资料

__pairs 和 __ipairs

现在,借助新的 __pairs 和 __ipairs 元方法,可以重载循环迭代。

参考资料: GeneralizedPairsAndIpairs

__len

除了字符串之外的所有类型现在都支持 __len 元方法。以前,__len 对于表是不支持的。

参考资料

%q 改进

string.format("%q") 现在可以转义控制字符。

参考资料

Goto 语句(包括模拟 continue 和带标签的 break 语句)

参考资料

字符串字面量中的十六进制表示法

除了旧的 \255 表示法之外,您还可以使用 \xFF 在字符串中写入。

参考资料

数值字面量中的十六进制小数和指数

您可以使用 0x0.A 或 0xA23p-4 的形式编写数值常量。在后一种情况下,'p' 表示以十进制表示的二进制指数(手册没有明确说明:我假设指数将像其他部分一样是十六进制的)。此功能在手写代码中可能没有用,但它允许使用 string.format 的十六进制选项对使用十六进制序列化数字进行精确反序列化。

但是,尽管包含了官方的位操作库,但仍然不支持二进制字面量。

参考资料

更安全的 os.date()

os.date() 现在只允许 ANSI C 选项。

参考资料

luaL_testudata()

新的 luaL_testudata API 函数,类似于 luaL_checkudata,但向调用者发出无效用户数据的信号,而不是抛出错误。

参考资料

常量折叠简化

如果第二个参数为零,则不再折叠除法和取模运算。

参考资料

更多 yield() 的自由

现在您可以在元方法、for 循环迭代器、pcall 和 xpcall 调用以及现在未记录的 table.foreach[i] 调用中使用 yield()。

此外,还提供了 C API 调用来实现您自己的支持 yield 的 C 函数。

位运算模块

现在,您可以在 Lua 中操作位,而无需第三方模块或补丁。虽然没有使用任何现有的实现。

参考资料

luaL_tolstring()

现在 luaL_tolstring 已记录。您可以通过 tostring() 规则正式将 Lua 值从 C 转换。

参考资料: [20]

新函数:lua_tonumberx 和 luatointegerx

参考资料

词法环境

_ENV

参考资料

getfenv() / setfenv() 已弃用

getfenv() 和 setfenv() 已被新的词法环境取代。调试库的对应函数仍然存在。

参考资料

函数/闭包构造优化

缓存匿名函数/闭包以供重用。由于移除了 getfenv/setfenv,现在可以进行此优化。待办事项:添加更好的描述和示例。

loadin()

新的 loadin(env,chunk) 函数用于在给定环境中加载代码块。请注意,chunk 参数也可以是字符串。

fn,err = loadin({x=1,y=2},"return x+y")

参考资料

load() 代码块类型过滤器

可以禁止加载字节码和/或源代码块。加载时的字节码验证已移除。

参考资料

Lua 线程环境

Lua 线程(也称为协程)不再拥有独立的环境。

参考资料:(有吗?)

ABI 和字节码不兼容

如预期,Lua 5.2 的 ABI 和字节码与 5.1 不兼容。

参考资料

5.1 中的弃用功能

5.1 中几乎所有弃用功能都被移除。新的弃用功能默认处于关闭状态。

参考资料:(有吗?)

调试模块不再默认加载

如果需要,请使用 require() 加载。

假设这是指调试库,在发布版本中似乎并非如此 - 调试库在 luaL_openlibs 加载的列表中。--JohnHind

参考资料

协程库升级为完整库

以前,协程库是基本库加载器函数加载的子库。在 5.2 中,它拥有自己的加载器函数,并升级为普通库。它包含在 luaL_openlibs 加载的列表中,因此此更改仅在运行时不使用 luaL_openlibs 时才重要。

手册中存在一个小错误:此更改反映在第 6 节中,但第 6.2 节仍然将其称为“基本库的子库”。

参考资料

debug.getlocal 参数名称

debug.getlocal 获取非活动函数的参数名称。在 debug.getlocal ([thread,] f, local) 中,“参数 f 也可以是一个函数。在这种情况下,getlocal 只返回函数参数的名称。”

参考资料

Upvalue 操作

新增函数用于检测两个 upvalue 是否相同,以及在它们不同时将它们合并

参考资料

额外的调试信息

debug.getinfo() 和 lua_getinfo() 现在返回关于调用栈上函数的额外信息

参考资料:(有吗?)

模式:%f 已记录

边界模式现在已记录。

参考资料

模式:%g

新模式 %g 代表除空格之外的所有可打印字符。

string.gsub repl

string.gsub [6] 现在如果替换字符串包含 '%' 后面跟着除允许的 '%' 或数字以外的字符,则会引发错误。

ipairs 行为变更(此功能已被撤回)

现在 ipairs() 迭代表中的 #t 个元素。在 5.1 中,它迭代到第一个 nil 为止。

参考资料: 源代码:lua-5.2.0-work4/src/lbaselib.c 第 213 行

select() 负数

您可以将负索引传递给 select() 以从可变参数的末尾获取参数(按直接顺序)。

参考资料

math.log10() vs. math.log()

math.log10() 已弃用。使用 10 作为 math.log() 的新第二个参数。

参考资料:(有吗?)

table.maxn() 已删除

table.maxn 已弃用。

参考资料

table.unpack() 和 table.pack()

unpack() 重命名为 table.unpack()。添加 table.pack(),将参数打包到表中并将参数数量存储到表的字段 "n" 中。

参考资料

增强管道支持

如果文件由 io.popen() 打开,file:close() 返回进程的退出代码。

参考资料

更好的停止 GC 处理

调用 collectgarbage("step") 不会再在 GC 停止时重新启动 GC。此外,您可以通过调用 collectgarbage("isrunning") 来判断 GC 是否已停止。当然,您也可以在 C API 中执行相同的操作。

参考资料:(有吗?)

标识符的区域设置

Lua 标识符不再可以使用依赖于区域设置的字符。

参考资料

新的注册表字段

以下是 5.2.0 版本中 Lua 使用注册表 (在伪索引 LUA_REGISTRYINDEX) 的完整列表。

由 lua_newstate 安装

由 'package' 库加载器安装

由 'IO' 库加载器安装

手册中说明:“与全局名称一样,以下划线后跟大写字母开头的字符串键保留给 Lua。” 但是请注意,Lua 并没有严格遵循此规则,例如 "FILE*" 键。

字符串的元表尚未在注册表中引用,但它只是索引字符串库表本身,因此添加到该库表中的函数将自动作为字符串对象的函数。

参考资料

轻量级 C 函数 / lua_cpcall 改进

lua_pushcfunction 不再分配内存。这更有效率,并且不会在失败时引发错误。它还消除了对 lua_cpcall() 的需求,该函数已从 API 中移除。此外,由于 lua_pcall 现在可以支持多个参数和返回值,因此不再需要支持多个参数和返回值的 lua_cpcall 版本。

LUA_GLOBALSINDEX 已移除

如果您需要它,请从注册表中使用 LUA_RIDX_GLOBALS(或者如果您没有更改 C 函数环境,则使用 LUA_ENVIRONINDEX)。

参考资料:(有吗?)

lua_getglobal()、lua_setglobal() 和 lua_register()

这些函数使用 C 函数环境而不是状态的全局环境,以更好地反映 Lua 处理全局变量的方式。

参考资料:(有吗?)

luaL_typerror() 已弃用

参考资料

lua_compare()

添加了新函数 lua_compare() 来替换已弃用的 lua_equal() 和 lua_lessthan()。

参考资料

lua_arith()

新函数 lua_arith() 用于像 Lua 一样对 Lua 值进行算术运算。

参考资料

从 C 获取对象长度

lua_objlen() 已重命名为 lua_rawlen()。添加了 lua_len() 来支持 __len 元方法。

参考资料

lua_checkstack() 更新

lua_checkstack 现在只返回错误代码(从不抛出)。如果要抛出(带错误字符串),请使用 luaL_checkstack。

参考资料

lua_pushstring() 和 lua_pushlstring() 增强

现在它们返回指向内部字符串表示的指针。

参考资料:(有吗?)

lua_copy()

允许在堆栈上复制 Lua 值(替换目标槽中的现有值)。

参考资料

Lua 运行时版本检查

添加了两个新函数 lua_version() 和 luaL_checkversion(),允许用户检查运行时版本和地址空间正确性。这将有助于防止在多个 Lua 实例链接到可执行文件时出现的可怕的难以理解的错误。luaL_checkversion() 从 luaL_register() 调用,因此当大多数模块被 require() 时,此类检查将自动执行。

参考资料

luaL_traceback()

新函数用于生成堆栈跟踪,就像 debug.traceback() 一样。

参考资料

LUA_ERRGCMM 和 LUA_OK

LUA_ERRGCMM 是一个新的运行时错误代码,用于表示 __gc 元方法中的错误。添加 LUA_OK 是为了保持对称性,表示一切正常,没有错误。

参考资料

*nix 上更好的动态库加载

现在 Lua C 模块可以使用全局符号加载动态库 (感谢 RTLD_GLOBAL)。

参考资料:(有吗?)

Windows 上的动态库加载改进

Windows 上的 DLL 搜索路径处理得到了改进。

每个块更多常量

每个块的最大常量数量从 2^18 增加到 2^26。去吧,巨大的表格转储!

参考资料

解析器优化

解析器消耗更少的 c-stack 空间,因为它不再使用自动数组。

参考资料

新的浮点数哈希函数

新的浮点数哈希函数,可以更好地处理在某些 64 位平台上 lua_Number 被定义为 long double 的情况。

参考资料

file:write() 改进

file:write() 返回文件以允许链式调用。

参考资料

新文件:read 和文件:lines 中的换行符保留

文件:read 的新 "*L" 选项类似于 "*l",但保留换行符 (如果存在)。此外,file:lines 中的新 keepNL 参数保留换行符。

os.exit() 优化

它可以选择在 Lua 状态上调用 lua_close()。

参考资料

os.execute() 接口变更

"os.execute 函数现在在命令成功终止时返回 true,否则返回 nil 和错误信息。" [10]

示例

$ lua51 -e "os.exit(3)"; echo $?
3
$ lua51 -e 'print(os.execute[[lua -e "os.exit(3)"]])'
768
$ lua52  -e 'print(os.execute[[lua -e "os.exit(3)"]])'
nil	exit	3
$ perl -e 'print(system(qq(perl -e "exit(3)")),"\n")'
768
$ python -c "import os; print(os.system(\"python -c 'import os; os._exit(3)'\"))"
768

Call` `Info 堆栈现在是链表

??

参考资料

解决模块系统和模块函数问题

module/luaL_register 函数已弃用,并被 luaL_newlib 和 luaL_setfuncs 替换。还新增了一个函数 luaL_requiref

我认为这比手册或其他资料中提到的变化要重大得多。表面上看,以前你可以写 require 'coroutine',例如,现在你必须写 coroutine = require 'coroutine'。这绝对是一个有用的改进,但如果我理解正确的话,它会破坏很多现有的代码。手册的“更改”部分对此不够明确。更糟糕的是,require 的文档没有清楚地说明返回值的用途。你必须从字里行间读出,其目的是返回模块的全局表或值 'true',如果模块没有导出全局表(实现此意图取决于模块加载器遵循一些规则,这些规则没有明确说明)。

手册中说“一旦找到加载器,require 就会用两个参数调用加载器:modname 和一个额外的值,该值取决于它是如何获取加载器的。[...] 如果加载器返回任何非 nil 值,require 会将返回的值分配给 package.loaded[modname]。如果加载器没有返回非 nil 值并且没有将任何值分配给 package.loaded[modname],那么 require 会将 true 分配给该条目。在任何情况下,require 都将返回 package.loaded[modname] 的最终值。” 这怎么不清楚?不过,我想补充一点,允许将 true 而不是模块表分配给 package.loaded[modname] 通常是应该避免的,并且更像是回退行为,缺乏任何更好的值可以使用,至少可以确保模块加载器在多次 require 调用时不会执行多次。现在,关于加载器应该返回什么,它通常应该是一个表 [21],但官方 Lua 参考手册可能对此保持沉默,因为 MechanismNotPolicy 设计原则。有时模块加载器会返回函数(通常是对象构造函数),尽管也许最好返回 FuncTables(即带有调用运算符的表),因为对于 require'foo'._VERSION 来表示模块版本 (ModuleVersioning) 是准标准的,这在 FuncTables 中仍然是可能的。顺便说一下,module 函数虽然在 5.2 中已弃用,但仍然可用,除非你关闭弃用功能,并且对 module 的调用会设置 package.loaded[modname](以及一个全局变量)。--DavidManura

比较 `luaL_requiref` (C API) 和 `require` (Lua):后者只接受模块名称,而前者接受模块名称、库加载器函数和一个标志,如果将该标志设置为 `true`,则将加载器函数的返回值存储在一个与库名称相同的全局变量中。`luaL_openlibs` 使用 `luaL_requiref` 并设置了此标志。因此,它将打开标准库,并按预期初始化其全局表。但是,从 Lua 使用 `require` 打开的库必须使用返回值显式设置全局变量。

如果您认为以上两段内容有误,请随时更正!

我认为 `luaL_requiref` 只是一个针对某些情况(如 linit.c)的便利函数。例如,它假设加载器是一个 C 函数 (lua_CFunction),目标表是 `LUA_RIDX_GLOBALS`,因此它并不完全通用。“必须显式设置全局变量”并不完全正确,因为通常首选显式设置局部变量,`local foo = require 'foo'`,它不会篡改 `_G`。--DavidManura

抱歉 DavidManura,我并没有真正打算发起政策讨论/批评,只是想提醒其他人注意我最近遇到的一个实际问题。我的运行时默认情况下不会加载大多数标准库,而是将它们的加载器函数放在 `preloads` 表中(我这样做是为了节省内存)。在从 5.1.4 转换为 5.2 后,我发现 Lua 使用例如 `require 'coroutine'` 不再工作,我不得不将其更改为 `coroutine = require 'coroutine'`。这导致了以下考虑:如果第三方库开发人员遵循标准库设置的示例(我不会说政策),那么他们也可能会破坏现有的 Lua 代码。大多数用户不会注意到标准库的这种变化,因为运行时通常通过调用 `luaL_openlibs` 来加载这些库,而 `luaL_openlibs` 又会调用 `luaL_requiref`。-- JohnHind

参考资料

特定于版本的环境变量

添加了环境变量 LUA_PATH_5_2 等。


我们在 5.2 中不会得到什么

...或者我们会得到吗?

欢迎您在这里添加您的宠物功能,假设它得到了列表中其他人的支持,并且被 Lua 作者拒绝纳入 5.2 版本。请保持礼貌。--AlexanderGladysh

string.pack/string.unpack

类似于 struct/lpack 的东西

参考资料

拒绝理由:(有链接吗?)

令牌过滤器

或其他“元”设施。

参考资料

拒绝理由:(有链接吗?)

#line 指令

这将类似于 C 预处理器的 #line 指令 [11]。主要目的是允许预处理器在生成的 Lua 代码中输出此指令,以便调试行号和文件名与原始(预处理前)源代码相对应。

移除自动强制转换

lua_rawtostring / rawtostring

从数字中获取一个没有强制转换的字符串。

参考资料

拒绝理由:(有链接吗?)

模块名称中的连字符

目前预计模块版本号位于名称的左侧,这很不寻常。

参考资料

拒绝理由:(有链接吗?)

改进确定性资源清理

用类似 package.clean 的东西替换 package.seeall

用类似于 ModuleDefinition 中的 package.clean 解决方案替换 package.seeall,但更新为支持 _ENV。package.seeall 不会将公共模块表与私有实现环境分开。

参考资料

建议

用户为 5.2 提出的某些功能/更改列在 FeatureProposals 中。请求应发布到邮件列表。

另请参阅


RecentChanges · preferences
edit · history
最后编辑于 2012 年 5 月 20 日凌晨 3:00 GMT (diff)