【问题标题】:Lua _G metatable not workingLua _G 元表不工作
【发布时间】:2015-11-29 02:37:13
【问题描述】:

我正在尝试控制交互环境。这是我的尝试:

home: lua
Lua 5.0.3  Copyright (C) 1994-2006 Tecgraf, PUC-Rio
> for n in pairs(_G) do io.write(n) end
stringxpcallLUA_PATHtostringgcinfoloadlibosunpackrequiregetfenvsetmetatablenext_TRACEBACKasserttonumberiorawequalcollectgarbagegetmetatable_LOADEDrawsetmathLUA_CPATHpcalldebug__powtypetablecoroutineprint_Gnewproxyrawgetloadstring_VERSIONdofilesetfenvpairsipairserrorloadfile> 
> G=_G
> _G={}
> setmetatable(_G,{__index=G,__newindex=function() print("nope") end})
> for n in pairs(_G) do io.write(n) end
> x=3
> 

我希望在命令“x=3”之后看到“nope”。然而,它通过了。 _G 不是空的吗,_G 的任何访问/更新都会经过定义的元方法?

【问题讨论】:

  • 顺便说一句,你为什么使用 lua 5.0?那是十年前的事了!使用 lua 5.3...

标签: lua metatable


【解决方案1】:

来自 Lua 5.0 手册:

_G

保存全局环境(即_G._G = _G)的全局变量(不是函数)。 Lua 本身不使用这个 多变的;改变它的值不会影响任何环境。 (采用 setfenv 改变环境。)

更具体地说,在交互式 Lua 解释器中,您需要 setfenv( 0, new_global_env ) 将当前运行线程的环境更改为 new_global_env

例子:

Lua 5.0.3  Copyright (C) 1994-2006 Tecgraf, PUC-Rio
> do
>> local rawget, print, _G = rawget, print, _G
>> local new_global_env = setmetatable( { tostring = tostring }, {
>>   __index = function( t, k )
>>     print( "get", k )
>>     return rawget( _G, k )
>>   end
>> } )
>> setfenv( 0, new_global_env )
>> end
> print( "hello" )
get print
hello
> 

rawgetprint_G 的上值以及新的 tostring 全局值对于避免无限递归是必要的。)

【讨论】:

  • setfenv(0,...) 解决了这个问题!我不太明白无限递归。再详细一点?
  • @user3015347:每当 Lua 尝试查找全局变量时,都会调用 __index 函数。在执行__index 时,会调用全局print 函数。由于全局环境不包含print 条目,因此再次调用__index 函数(并再次...)。 rawget_G 相同,它们也用于 __index 函数。全局tostringprint 函数在内部调用,以将其参数转换为字符串以供输出。在这种情况下不能使用上值,因为我们无权访问 print 的定义。
  • 谢谢,siffiejoe,我想我听从了你的解释。现在我开始担心rawget()中使用了哪些函数,如果它的定义中需要print、_G、tostring以外的函数,会不会再次出现无限递归?
  • 没有你想的那么糟糕。大多数 C 函数不访问全局变量——print 几乎是 Lua 标准库中的 异常。而Lua函数反正不一样,保存的是当前运行线程在创建函数时所拥有的全局环境的值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
  • 2011-09-01
  • 2014-12-21
  • 2018-12-28
  • 1970-01-01
  • 1970-01-01
  • 2014-01-31
相关资源
最近更新 更多