Lua 函数、闭包、尾调用总结


《lua 程序设计》在线阅读:http://book.luaer.cn/


1.函数

函数有两种用途:
  • 完成指定的任务,这种情况下函数作为调用语句使用;
  • 计算并返回值,这种情况下函数作为赋值语句的表达式使用。

1.1 语法

function func_name (arguments-list)
    statements-list;
end;
示例

function foo (x) return 2*x end
foo = function (x) return 2*x end
从上面我们可以看出lua函数定义实际上是一个赋值语句,将类型为function的变量赋给一个变量,需注意:

  • 调用函数的时候,如果参数列表为空,必须使用()表明是函数调用。
  • 当函数只有一个参数并且这个参数是字符串或者表构造的时候,()可有可无,例如
print "Hello World"      <-->       print("Hello World")

1.2 返回值

lua函数可以返回多个值
function foo0 () end                   -- returns no results
function foo1 () return 'a' end        -- returns 1 result
function foo2 () return 'a','b' end    -- returns 2 results
需注意返回多个值是:
  1. 多返回值的函数必须是作为表达式最后一个参数,否则只返回一个值
  2. 接收的话不足补nil,超出舍去,如
x,y = foo2()             -- x='a', y='b'
x,y = foo1();            -- x = 'a', y= nil 
x = foo2()               -- x='a', 'b'舍去
x,y = foo2(), 20         -- x='a', y=20
另外,括号可以强制返回一个值
print((foo2()))      --> a

1.3 可变参数

  • 可变参数用...来表示
  • Lua将函数的可变参数放在一个叫arg的表中,除了参数以外,arg表中还有一个域n表示参数的个数。
function fn(name,nick,...)
    print(name,nick)      -- 一撮毛  大帅锅
  for i,v in ipairs(arg) do
       print(arg[i])      -- 1,2,3,4
    end
end
fn("毛毛","大帅锅",1,2,3,4);  -- name="毛毛",nick="大帅锅",arg={1,2,3,4; n = 4}

2.函数闭包

当一个函数内部嵌套另一个函数定义时,内部的函数体可以访问外部的函数的局部变量,这种特征我们称作词法定界。
先看如下代码:

function fn()
    local i = 0
    return function()     -- 注意这里是返回函数的地址,不是执行
       i = i + 1
        return i
    end
end

c1 = fn()           -- 接收函数返回的地址
print(c1())  --> 1          --c1()才表示执行
print(c1())  --> 2
如上,调用c1()时,fn函数明显已经返回,lua闭包闭包思想正确处理这种情况:

  • 我们称i为从c1的外部局部变量(external local variable)或者upvalue。
  • 简单的说,闭包是一个函数以及它的upvalues
如果我们再次调用fn,将创建一个新的局部变量i:

c2 = fn()
print(c2())  --> 1
print(c1())  --> 3
print(c2())  --> 2

3.函数尾调用

  • 尾调用是一种类似在函数结尾的goto调用。
  • 当函数最后一个动作是调用另外一个函数时,我们称这种调用尾调用。

例如:

function f(x)
    return g(x)  -- 类似于goto g(x)函数的地址
end

  • 尾调用不需要使用栈空间,因此尾调用递归的层次可以无限制的。

例如下面调用不论n为何值不会导致栈溢出。

function foo (n)
    if n > 0 then return foo(n - 1) end
end
需要注意的是:必须明确什么是尾调用。
一些调用者函数调用其他函数后也没有做其他的事情但不属于尾调用。比如:

function f (x)
    g(x)
    return
end
上面这个例子中f在调用g后,不得不丢弃g地返回值,所以不是尾调用,同样的下面几个例子也不时尾调用:
return g(x) + 1      -- 还需+1
return x or g(x)     -- 还需比较
return (g(x))        -- 还需调整为一个返回值





posted @ 2014-08-22 15:54  会做菜的老狼  阅读(436)  评论(0编辑  收藏  举报