这篇文章主要介绍了Lua中的函数(function)、可变参数、局部函数、尾递归优化等实例讲解,需要的朋友可以参考下 一、函数 在Lua中,函数是作为"第一类值"(First-Class Value),这表示函数可以存储在变量中,可以通过参数传递给其他函数,或者作为函数的返回值(类比C/C++中的函数指针),这种特性使Lua具有极大的灵活性。 复制代码 代码如下: function hello() print('hello') end hello函数不接收参数,调用:hello(),虽然hello不接收参数,但是还可以可以传入参数:hello(32) 复制代码 代码如下: > hello '3' hello > hello {} hello > hello 3 stdin:1: syntax error near '3' 另外对变量名也不适用 复制代码 代码如下: > a = 21 > print a stdin:1: syntax error near 'a' 另外,Lua函数不支持参数默认值,可以使用or非常方便的解决(类似Javascript) 复制代码 代码如下: > function f(n) >> n = n or 0 >> print(n) >> end > f() 0 > f(1) 1 Lua支持返回多个值,形式上非常类似Python: 复制代码 代码如下: > function f() >> return 1,2,3 >> end > a,b,c = f() > print(a .. b .. c) 123 函数调用的返回值可以用于table: 复制代码 代码如下: > t = {f()} > print(t[1], t[2], t[3]) 1 2 3 可见,f()返回的三个值分别称为table的3个元素,但是情况并不总是如此: 复制代码 代码如下: > t = {f(), 4} > print(t[1], t[2], t[3]) 1 4 nil 这次,f()返回的1,2,3只有1称为table的元素; 复制代码 代码如下: > t = {f(), f()} > print(t[1], t[2], t[3], t[4], t[5]) 1 1 2 3 nil 总之:只有最后一项会完整的使用所有返回值(假如是函数调用)。 对于无返回值的函数,可以使用(f())的形式强行返回一个值(nil) 复制代码 代码如下: > function g() >> end > print(g()) > print((g())) nil 实际上,(f())形式的调用返回一个且只返回一个值 复制代码 代码如下: > print((f())) 1 > print(f()) 1 2 3 二、变长参数 Lua支持编程参数,使用简单(借助于table、多重赋值) 复制代码 代码如下: > function f(...) for k,v in ipairs({...}) do print(k,v) end end > f(2,3,3) 1 2 2 3 3 3 使用多重赋值的方式 复制代码 代码如下: > function sum3(...) >> a,b,c = ... >> a = a or 0 >> b = b or 0 >> c = c or 0 >> return a + b +c >> end > =sum3(1,2,3,4) 6 > return sum3(1,2) 3 通常在遍历变长参数的时候只需要使用{…},然而变长参数可能会包含一些nil;那么就可以用select函数来访问变长参数了:select('#', …)或者 select(n, …) select('#', …)返回可变参数的长度,select(n,…)用于访问n到select('#',…)的参数 复制代码 代码如下: > =select('#', 1,2,3) 3 > return select('#', 1,2, nil,3) 4 > =select(3, 1,2, nil,3) nil 3 > =select(2, 1,2, nil,3) 2 nil 3 注意:Lua5.0中没有提供…表达式,而是通过一个隐含的局部table变量arg来接收所有的变长参数,arg.n表示参数的个数; 三、函数式编程 函数做一个First-Class Value可以赋值给变量,用后者进行调用 复制代码 代码如下: > a = function() print 'hello' end > a() hello > b = a > b() hello 匿名函数 复制代码 代码如下: > g = function() return function() print 'hello' end end > g()() hello 函数g返回一个匿名函数; 闭包是函数式编程的一种重要特性,Lua也支持 复制代码 代码如下: > g = function(a) return function() print('hello'.. a); a = a + 1 end end > f = g(3) > f() hello3 > f() hello4 四、局部函数 局部函数可以理解为在当前作用域有效的函数,可以用local变量来引用一个函数: 复制代码 代码如下: > do >> local lf = function() print 'hello' end >> lf() >> end hello > lf() stdin:1: attempt to call global 'lf' (a nil value) stack traceback: stdin:1: in main chunk [C]: in ? 需要注意的是,对于递归函数的处理 复制代码 代码如下: > do local lf = function(n) if n <= 0 then return end print 'hello' n = n -1 lf(n) end lf(3) end hello stdin:8: attempt to call global 'lf' (a nil value) stack traceback: stdin:8: in function 'lf' stdin:9: in main chunk [C]: in ? 而应该首先声明local lf, 在进行赋值 复制代码 代码如下: do local lf; lf = function(n) if n <= 0 then return end print 'hello' n = n -1 lf(n) end lf(3) end hello hello hello Lua支持一种local function(…) … end的定义形式: 复制代码 代码如下: > do local function lf(n) if n <= 0 then return end print 'hello' n = n -1 lf(n) end lf(3) end hello hello hello > lf(3) stdin:1: attempt to call global 'lf' (a nil value) stack traceback: stdin:1: in main chunk [C]: in ? 五、尾调用 所谓尾调用,就是一个函数返回另一个函数的返回值: 复制代码 代码如下: function f() … return g() end 因为调用g()后,f()中不再执行任何代码,所以不需要保留f()的调用桟信息;Lua做了这样的优化,称为"尾调用消除",g()返回后,控制点直接返回到调用f()的地方。 这种优化对尾递归非常有益,通常递归意味着调用桟的不断增长,甚至可能造成堆栈溢出;而尾递归提供了优化条件,编译器可以优化掉调用桟。 下面的递归函数没有使用尾递归,而参数为大数时,堆栈溢出: 复制代码 代码如下: > function f(n) >> if n <= 0 then >> return 0 >> end >> a = f(n-1) >> return n * a >> end > f(10000000000) stdin:5: stack overflow stack traceback: stdin:5: in function 'f' stdin:5: in function 'f' stdin:5: in function 'f' stdin:5: in function 'f' stdin:5: in function 'f' stdin:5: in function 'f' stdin:5: in function 'f' stdin:5: in function 'f' stdin:5: in function 'f' stdin:5: in function 'f' ... stdin:5: in function 'f' stdin:5: in function 'f' stdin:5: in function 'f' stdin:5: in function 'f' stdin:5: in function 'f' stdin:5: in function 'f' stdin:5: in function 'f' stdin:5: in function 'f' stdin:5: in function 'f' stdin:1: in main chunk [C]: in ? 优化为尾递归 复制代码 代码如下: function f(n, now) if n <= 0 then return now end return f(n-1, now*n) end f(10000000000, 1) 运行n久也无堆栈溢出; 您可能感兴趣的文章:相关文章
最新评论 |
|