Lua中的函数(function)、可变参数、局部函数、尾递
归优化等实例讲解
⼀、函数
在Lua中,函数是作为"第⼀类值"(First-Class Value),这表⽰函数可以存储在变量中,可以通过参数传递给其他函数,或者作为函数的返回值(类⽐C/C++中的函数指针),这种特性使Lua具有极⼤的灵活性。
Lua对函数式编程提供了良好的⽀持,可以⽀持嵌套函数。
另外,Lua既可以调⽤Lua编写的函数,还可以调⽤C语⾔编写的函数(Lua所有的标准库都是C语⾔写的)。
定义⼀个函数
复制代码代码如下:
function hello()
print('hello')
end
hello函数不接收参数,调⽤:hello(),虽然hello不接收参数,但是还可以可以传⼊参数:hello(32)
另外如果只传递⼀个参数可以简化成functionname arg的调⽤形式(注意数值不⾏)
复制代码代码如下:
> 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()
> 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()
四、局部函数
局部函数可以理解为在当前作⽤域有效的函数,可以⽤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的定义形式:
复制代码代码如下:
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'
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论