我对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 ?
这没关系,因为根据explanation, 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 的例子,就像它在第一个例子中一样吗?
答案 0 :(得分:7)
引用全局func的第二个例子不是第一个例子吗?
是:)
您可以看到,编译新函数时是否存在值无关紧要。它不检查存储在func
变量中的值,而是每次调用时都会查找它。唯一重要的是变量的可见性。如果变量在本地范围内不可见,则它被视为全局变量,并将在全局环境表中查找。有关详细信息,请参阅Lua手册,第3.5 – Visibility Rules章
第一个示例不起作用,因为在计算完整表达式之前,local func
变量不可见。这就是为什么第一个例子中断,试图调用缺少的全局变量。
如果您希望该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)
可见,因此它将读取从该特定上限值调用的值。
请注意,通过稍后在func
变量中指定不同的内容,仍然可以“中断”该功能。 Lua中的函数(与任何其他值一样)没有名称,只有变量。因此,对函数的调用不是硬编译的,调用的函数值总是在每次调用之前从变量中获取。
答案 1 :(得分:2)
函数是值,因此如果没有问题的上下文,标题中的“全局函数”本身就不会感知。
变量绑定是编译器将代码中的标识符映射到变量的过程。关于变量绑定的问题通常出现在递归函数上,但绑定规则更简单,更通用。它们与递归,函数定义甚至本地与全局无关。尽管如此,函数定义语句的语法糖可能会混淆问题。
例如:
local x = x + 1
表达式中的 x
不是正在创建的x
。它取决于上面的任何代码。它可以是在语句块中声明的本地或作为函数参数。这样的声明可以在相同的块或函数定义中,也可以在外部的上面。全球只是后备。
显然,如果上面的示例中没有使用local
,则相同的名称将绑定到同一个变量。
y = y + 1
两个y
名称都是相同的变量,但如上所述,哪个变量由其他代码确定。
此函数定义语句类似:
function f() end
如果本地f
在范围内,那么这是编译器将“f”绑定到的变量,否则在全局环境中为“f”。