lua中的全局和局部递归函数

时间:2018-01-11 14:32:07

标签: variables recursion lua scripting-language

我对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 的例子,就像它在第一个例子中一样吗?

2 个答案:

答案 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)

@Vlad answers这个问题很好。为清晰起见,有几个问题指出了问题:

  1. 函数是值,因此如果没有问题的上下文,标题中的“全局函数”本身就不会感知。

  2. 变量绑定是编译器将代码中的标识符映射到变量的过程。关于变量绑定的问题通常出现在递归函数上,但绑定规则更简单,更通用。它们与递归,函数定义甚至本地与全局无关。尽管如此,函数定义语句的语法糖可能会混淆问题。

  3. 例如:

    local x = x + 1 
    
    表达式中的

    x不是正在创建的x。它取决于上面的任何代码。它可以是在语句块中声明的本地或作为函数参数。这样的声明可以在相同的块或函数定义中,也可以在外部的上面。全球只是后备。

    显然,如果上面的示例中没有使用local,则相同的名称将绑定到同一个变量。

     y = y + 1
    

    两个y名称都是相同的变量,但如上所述,哪个变量由其他代码确定。

    此函数定义语句类似:

     function f() end
    

    如果本地f在范围内,那么这是编译器将“f”绑定到的变量,否则在全局环境中为“f”。