在Lua 5.1中,可以将 environment 表与userdata相关联。这让我们可以添加"字段"个人用户数据。
显而易见的方法是在创建userdata 时创建此环境表,可能是空的,。但是,在我的应用程序中,会有许多用户数据,它们不一定需要这个环境表,它们会快速地出现。我不想要创建那么多不能使用的临时空表的开销。
所以,相反,我想到只有当我检测到用户数据还没有我创建的用户数据时才创建环境表。
问题是在Lua 5.1中,默认环境表不是nil
。它应该是全球表,_G
(我想知道它究竟是如何有用的)。因此,据说,我通过执行以下操作来测试未初始化的用户数据:
/* 'index' is where my userdata is */
lua_getfenv(L, index);
initialized = lua_rawequal(L, index, LUA_GLOBALSINDEX);
现在,我的问题:
我需要使用LUA_ENVIRONINDEX或LUA_GLOBALSINDEX吗?或者我还需要做其他事情吗?这个测试是否适用于绝对任何场景?
答案 0 :(得分:1)
通常,您将遇到全局表_G
或package
表作为userdata的默认环境,具体取决于调用lua_newuserdata
的C函数的函数环境(请参阅here })。通过require
加载的扩展模块中的用户数据通常具有package
表作为默认环境,因为require
将该表设置为环境,并且它由所有已注册的C函数继承并且创建了userdatas在他们里面。另一方面,newproxy
将_G
设置为默认环境。
原则上,如果有人更改了C函数的函数环境,那么你可以将任何表作为默认环境(这是非常罕见的)。在实践中,检查_G
和package
表可能就足够了。为此,您需要有关userdata的环境表的有效索引,package
表和全局表:
lua_getfenv( L, index ); /* pushes the environment of the ud to stack */
lua_getglobal( L, "package" ); /* pushes the package table to stack */
/* the globals table is always available at LUA_GLOBALSINDEX, so no need to push
* anything ... */
hasdefaultenv = lua_rawequal( L, -2, -1 ) /* compare env to package table */
|| lua_rawequal( L, -2, LUA_GLOBALSINDEX ); /* compare env to _G */
您可能希望将package
表保存在某处(例如,在upvalue中),这样任何人都无法通过替换package
表来破坏您的测试。
然而,最强大的解决方案是在创建userdatas时将一个唯一的共享虚拟表设置为环境(您可以使用_G
),并在必要时检查并替换该虚拟表。 / p>
顺便说一下,LUA_ENVIRONINDEX
用于获取currently running C function的环境,而不是用于获取用户数据的环境。