我对 lua 很陌生,我想了解以下行为。
当我尝试运行以下递归函数时:
local func = function ( n )
if n == 1 then return 1
else return n * func( n - 1 )
end
end
print( func( 5 ) )
程序将失败并出现错误:
lua: main.lua:16: attempt to call a nil value (global 'func')
stack traceback:
main.lua:16: in local 'func'
main.lua:38: in main chunk
[C]: in ?
没关系,因为根据解释,func变量的本地版本尚不清楚,因此它尝试调用全局变量。但是当我删除 local 关键字时,以下代码可以正常工作吗?
func = function ( n )
if n == 1 then return 1
else return n * func( n - 1 )
end
end
print( func( 5 ) )
程序打印 120 作为结果,但全局 func 之前从未初始化或使用过。这怎么可能也不会引发错误?第二个示例不是像第一个示例一样引用全局 func 吗?
第二个示例不是像第一个示例一样引用全局 func 吗?
是:)
你看,当你编译新函数时,值存在与否并不重要。 Lua 在编译时不会检查
func
变量中存储的值,而是每次调用时 Lua 都会查找它。编译期间唯一重要的是变量的可见性。如果变量在局部范围内不可见,则它被视为全局变量,并将在全局环境表中查找。有关更多详细信息,请参阅 Lua 手册,第 3.5 – 可见性规则
第一个示例不起作用,因为在计算完整的表达式之前,
local func
变量不可见。这就是第一个示例失败的原因,尝试调用丢失的全局变量。
如果您希望该函数是局部的,请声明该变量,然后然后分配它。喜欢:
local func
func = function ( n )
if n == 1 then return 1
else return n * func( n - 1 )
end
end
print( func( 5 ) )
对于这种情况,使用 Lua 的语法糖可能会更容易:
local function func( n )
if n == 1 then return 1
else return n * func( n - 1 )
end
end
print( func( 5 ) )
它将被完全翻译为声明变量的相同顺序,然后分配它。
这次
func
变量将对新的 function(n)
可见,因此它将读取要从该特定 upvalue 调用的值。
请注意,稍后仍然可以通过向
func
变量分配不同的内容来“破坏”该函数。 Lua 中的函数(和任何其他值一样)没有名称,只有变量有名称。因此,对函数的调用不是硬编译的,要调用的函数值始终在每次调用之前从变量中获取。
@Vlad 很好地回答了问题。为了清楚起见,关于这个问题的几点:
定义甚至本地与全局没有任何关系。尽管如此,函数定义的语法糖语句可能会混淆问题。
local x = x + 1
表达式中的
x
并不是正在创建的
x
。它是哪个变量取决于上面的任何代码。它可以是在语句块中声明的局部变量或作为函数参数。这样的声明可以位于同一块或函数定义中,或者位于外部块或函数定义中。全球只是后备方案。显然,如果上面的示例中没有使用
local
,则相同的名称将绑定到相同的变量。
y = y + 1
两个 y
名称是相同的变量,但如上所述,哪个变量是由其他代码确定的。
这个函数定义语句类似:
function f() end
如果本地
f
在范围内,那么编译器将“f”绑定到该变量,否则“f”在全局环境中。