Lua的尾调用和循环

我正在使用Lua编写一个小的CLI模块,以便在C程序中嵌入使用。

我想知道在处理提示选择时最佳方法,应该是使用尾调用还是循环

如果使用尾调用,我会像下面这样做:

call = { help=function () print 'just ask politely' end }

function shell ()
  io.write ('% ')
  local cmd = io.read ()

  if cmd ~= 'quit' then
    call[cmd] () -- 假设call[cmd]的值始终非nil,为了简便
    return shell ()
  end
end

我想问以下几个问题:

  1. 这是正确的使用和实现_tail-call elimination_的吗? call[cmd]()是否在堆栈中引入了任何干扰,以便我不能利用_tail-call elimination_?

  2. 是否最好使用如下的循环? 如果是,为什么?

    repeat
      io.write ('% ')
      local cmd = io.read()
    
      -- do stuff
    until cmd == 'quit'
    
  3. 在《Lua程序设计》中有如下说明

    一个_tail call_是一个伪装成函数调用的_goto_语句。

    所以尾调用和循环之间有任何具体差别吗?

谢谢。

点赞
用户734069
用户734069

这是尾调用消除的正确使用/实现吗?

如果你在问在 Lua 语法中,结尾的 shell 调用是否是正确的尾调用,答案是肯定的

call[cmd]()会不会对堆栈造成干扰,使我不能利用尾调用消除?

函数调用不会修改你所想的方式修该栈。在 Lua 中,尾调用唯一要求的是它应该是return Function(params)形式的,没有额外的返回值,并且返回的值必须来自函数。

一个正确的尾调用甚至不需要调用它自己;它不需要是递归的。

使用以下循环是否更好?如果是,为什么?

这是一个主观问题。就我个人而言,我认为循环更清晰。

然而,如果你想得出一个关于性能的客观问题,请考虑以下内容:尾调用永远不会_快于_循环。你在性能方面所能得到的最好结果是相等的。

而实际上可能并不会是这样。Lua 的尾调用“优化”仅仅意味着它重新使用当前函数的堆栈条目。Lua 仍然必须从全局表中获取函数。Lua 仍然必须执行调用一个函数的所有开销;它只是不必分配更多的堆栈内存。

这实际上是关于不会溢出堆栈,而且不会在不必要时分配内存的问题。

尾调用和循环之间是否有任何具体的区别?

请参阅上文。

2012-07-20 20:16:07