Lua语言是支持尾调用消除的(tail-call elimaination),这意味着Lua语言可以正确尾递归(tail-recursive)。

尾调用是被当做函数调用使用的跳转。当一个函数的最后一个动作是调用另一个函数而没有再进行其他工作时,就形成了尾调用。比如下面的代码中对函数g的调用就是一个尾调用。

function f (x)
    x = x + 1;
    return g(x)
end

当函数f调用完函数g之后,f不再需要进行其他的工作。这样一来,当被调用的函数执行结束后,程序就不再需要返回最初的调用者。因此,在尾调用之后,程序也就不需要在调用栈中保存有关调用函数的任何信息。当函数g返回时,程序的执行路径将直接返回到调用f的位置。利用这个特点,尾调用时就不需要使用额外的栈空间,对于递归的空间占用效率是很好的优化。

在Lua语言中,只有形如 return func(args) 的调用才是尾调用。

输入和输出

由于Lua语言强调可移植性和嵌入型,所以Lua语言本身并没有提供太多与外部交互的机制。

简单I/O模型

简单模型虚拟了一个当前输入流和一个当前输出流,其I/O操作是通过这些流实现的。 I/Ok库把当前输入流初始化为进程的标准输入,将当前输出流初始化为进程的标准输出。

io.input(filename)会以只读模式打开指定文件,并将文件设置为当前输入流。

io.write可以读取任意数量的字符差并将其写入当前输出流。io.write允许对输出进行重定向,而函数print只能使用标准输出。

io.read可以从当前输入流中读取字符串,其参数决定了要读取的数据

  • “a” --- 读取整个文件
  • “l” ---- 读取下一行(丢弃换行符)
  • “L” --- 读取下一行(保留换行符)
  • "n" --- 读取一个数值
  • num --- 以字符串读取num个字符

如果要逐行迭代一个文件,那么用io.lines迭代器更简单:

下面这个程序读取文件并排序

local lines = {}

for line in io.lines do
    lines[#lines + 1] = line
end

table.sort(lines)

for _, l in ipairs(lines) do
    io.write(l, "\n")
end