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()

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久也无堆栈溢出;

时间: 2024-08-03 19:21:19

Lua function函数,可变参数, 局部函数,尾递归优化的相关文章

可变参数的函数(variadic function)的陷阱

1,介绍variadic function 可变参数的函数就是参数数量可以改变的函数.例如printf(): int printf(const char *format, ...); printf("%d%s\n",i,s); C语言之所以可以支持可变参数函数,一个重要的原因是C调用规范中规定C语言函数调用时,参数是从右向左压入栈的:这样一个函数实现的时候,就无需关心调用他的函数会传递几个参数过来,而只要关心自己用到几个:例子: #include<stdarg.h> voi

PHP函数可变参数列表的具体实现方法介绍

PHP函数可变参数列表可以通过_get_args().func_num_args().func_get_arg()这三个函数来实现.我们下面就对此做了详细的介绍. AD:2014WOT全球软件技术峰会北京站 课程视频发布 也许对于PHP初级程序员来说,对于PHP函数并不能完全熟练的掌握.我们今天为大家介绍的PHP函数可变参数列表的实现方法主要是利用func_get_args().func_num_args().func_get_arg()这三个系统函数来实现的,其中func_get_args()

C语言之函数可变参数

先上一段代码: #include<cstdarg> #include<iostream> #include<string> using namespace std; void error(char* format,...){//至少要有一个参数,后边的...表示参数可变 va_list ap; int d,flag; char c, *s; va_start(ap,*format);//从args参数开始后面都是可变参数,va_start,va_end都为宏 while

可变参数的函数与宏

1.可变参数的函数 <stdarg.h>头文件中定义了一些宏,用于可变参数的函数,如下 va_list:这种类型声明局部状态变量,假设变量名为va(用于下面的描述),用于遍历函数. va_start:这个宏初始化状态变量va,要先调用之后才能调用va_arg与va_end. va_arg:这个宏返回参数表中下一个参数的值,将内部指针(在va中)移到下一个参数,下一个参数的类型要用type指定,使va_arg能够计算其在堆栈中的长度,调用va_start之后第一次调用va_arg返回第一个可变参

php课外笔记--函数可变参数列表的实现

php课外笔记--函数可变参数列表的实现 php的函数方面非常强大,但对于一些php新手来说,理解有部分困难,不能完全熟练的掌握. php培训教程中,介绍一部分函数可变参数列表的实现方法: PHP函数可变参数列表的实现方法主要是利用func_get_args().func_num_args().func_get_arg()这三个系统函数来实现的,其中func_get_args()函数以数组的形式获得参数列表,具体用法参看手册. PHP函数可变参数列表代码如下: < ?php    /*   函数

函数可变参数

VA_LIST的用法:(1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针: (2)然后用VA_START宏初始化变量刚定义的VA_LIST变量,使其指向第一个可变参数的地址: (3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型(如果函数有多个可变参数的,依次调用VA_ARG获取各个参数): (4)最后用VA_END宏结束可变参数的获取.使用VA_LIST应该注意的问题: (1.可变参数的类型和个数完全由程序代码控制,它并不能智能地识别不

C语言函数可变参数列表

C语言允许使用可变参数列表,我们常用的printf函数即为可变参数函数,C标准库提供了stdarg.h为我们提供了这方面支持:该头文件提供了一些类型和宏来支持可变参数列表,包括类型va_list,宏va_start.va_arg.va_end: 可变函数参数定义方法: #include <stdarg.h> void func(int count,...){ va_list ap; int ix, tmp; va_start(ap, a); for(ix=0;ix < count; ++

Objective-C可变参数的函数实现

1.前言 相信接触过OC的对NSLog都很熟悉,细心查看NSLog的原始定义,会发现,他的原型如下: FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2); 路径在:OS X version/Frameworks/Foundation/NSObjCRuntime.h 注意到参数最后的...,这里是可变参数.这样,在调用时就可以根据需要传入相应个数的参数了. PS:其实在C#中也有params指定可变

C语言利用va_list、va_start、va_end、va_arg宏定义可变参数的函数

在定义可变参数的函数之前,先来理解一下函数参数的传递原理: 1.函数参数是以栈这种数据结构来存取的,在函数参数列表中,从右至左依次入栈. 2.参数的内存存放格式:参数的内存地址存放在内存的堆栈段中,在执行函数的时候,从最后一个(最右边)参数开始入栈.因此栈底高地址,栈顶低地址,举个例子说明一下: void test(int a, float b, char c); 那么,在调用test函数的时候,实参char c先进栈,然后是float b,最后才是int a,因此在内存中变量的存放次序是c->

c 语言函数可变参数的处理

/************************************************************************* > File Name: va_list.c > Author: zshh0604 > Mail: [email protected] > Created Time: 2014年10月14日 星期二 15时16分09秒 **********************************************************