在Lua中,把嵌套函数设为全局函数有什么意义?
这是Knuth的“Man/Boy Test”的Lua版本。为了复现 维基百科的条目 中显示的结果,我发现必须把嵌套的函数B 声明为local。我不明白这是为什么。
-- Knuth's Man-Boy test for ALGOL60
-- but I want to understand the critical matter of "local" in front
-- of the inner function
ftab = {} ;
ftab.n = 0 ;
function fs( f )
local s ;
s = tostring( f ) ;
s = s:sub( 10 ) ;
if ftab[f] == nil then
ftab.n = ftab.n + 1 ;
ftab[f] = string.format( "f%03d", ftab.n ) ;
end ;
s = " " .. ftab[f] ;
return s ;
end ; -- fs
function is( n )
local s ;
s = string.format( "%3d", n ) ;
return s ;
end ; -- is
function A(k,x1,x2,x3,x4,x5)
print( " A" .. fs(A) .. is(k) .. fs(x1) .. fs(x2) .. fs(x3) .. fs(x4)
.. fs(x5), _G, _ENV ) ;
--local
function B()
print( " B" .. fs(B) .. is(k) .. fs(x1) .. fs(x2) .. fs(x3) .. fs(x4)
.. fs(x5), _G, _ENV ) ;
k = k - 1 ;
return A( k, B, x1, x2, x3, x4 ) ;
end ; -- B
local v ;
if k <= 0 then v = x4() + x5() ; else v = B() ; end ;
return v ;
end ; -- A
function K(n)
function Kn()
return n ;
end ; -- Kn
return Kn ;
end ; -- K
print( "A = ", A ) ;
print( "B = ", B ) ;
print( "_G = ", _G ) ;
print( "_ENV = ", _ENV ) ;
print( "A -> ", A( 5, K(1), K(-1), K(-1), K(1), K(0) ) ) ;
print( "A = ", A ) ;
print( "B = ", B ) ;
print( "_G = ", _G ) ;
print( "_ENV = ", _ENV ) ;
A = function: 00dfae58 f001
B = nil fnil
_G = table: 00df2d78
_ENV = table: 00df2d78
A f001 5 f002 f003 f004 f005 f006
B f007 5 f002 f003 f004 f005 f006
A f001 4 f007 f002 f003 f004 f005
B f008 4 f007 f002 f003 f004 f005
A f001 3 f008 f007 f002 f003 f004
B f009 3 f008 f007 f002 f003 f004
A f001 2 f009 f008 f007 f002 f003
B f010 2 f009 f008 f007 f002 f003
A f001 1 f010 f009 f008 f007 f002
B f011 1 f010 f009 f008 f007 f002
A f001 0 f011 f010 f009 f008 f007
B f012 3 f007 f002 f003 f004 f005
在调用函数A 之前,B为 nil——即使B 是全局变量也一样。A第一次返回后,如果B 是local,那么B(那个不存在的全局变量)再次为nil。
我搞不懂的是,B的全局性为什么会影响执行?使用“local function B”时,最终结果是“0”;不使用“local”时,最终结果是“1”。
我追溯到A 第一次调用且k < 1的情形。对B 的下一次调用并不能将自身识别为A 的x4参数,尽管它“看见”了应该对x4参数可见的A 的参数。
这时我就放弃去设想可能的原因。有人把我从痛苦中解救出来了。
解决方案
我看了维基百科的那篇文章和你的代码,完全不知道那个算法在做什么,不过我确实知道Lua函数是怎么定义的。
函数可以是局部变量,也可以是全局变量;当你在A 函数内部定义B 函数时,如果在定义前不加local,那么B 就会成为一个全局变量。
另外,还有上值(upvalues)。每当Lua的控制流经过一个函数定义时,就会为该函数创建一个新的闭包,并能够访问在该闭包中捕获的局部变量(若有的话)。(更多信息: https://www.lua.org/pil/6.1.html)
在你的代码中,每次调用A 时,如果把B 定义为全局函数,那么全局变量B 会被新的闭包覆盖。于是对B 的后续调用就会执行B 的最新定义。
但如果把B 定义为局部函数,它就不会覆盖B 之前的闭包。于是对B 的后续调用取决于所引用的是哪一个B 的闭包。
另外还要注意的是,如果一个变量是全局的,它永远不会成为上值(因为全局变量只存在于单一的 _G表中,而局部变量可以在每个闭包中独立存在)。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。