基础知识:
lua中函数主要有两种作用:
1.完成指定的任务,这种情况下函数作为调用语句使用;
2.计算并返回值,这种情况下函数作为赋值语句的表达式使用。
函数的定义形式如下:
optional_function_scope function function_name( argument1, argument2, argument3..., argumentn) function_body return result_params_comma_separated end
其中:
optional_function_scope表示可选的局部函数标志,如果该标记未设定,表明该函数为全局函数,如果该标记被设置为local,表明该函数为局部函数。
argument等为参数;
result_params_comma_separated表示返回值序列,需要注意的一点是,lua支持函数返回多个值。就像多值赋值一样,如果要接收多个返回值,需要多个变量来接收。如果变量数量不够,则多余的返回值被丢弃。如果变量数量多于返回值数量,多余的变量会被设置为nil。返回值序列中,多个值之间以逗号分隔开。
例子如下:
function max(num1, num2) if (num1 > num2) then result = num1; else result = num2; end return result; end print("两值比较最大值为 ",max(10,4)) --> 10 print("两值比较最大值为 ",max(5,6))<span style="white-space:pre"> </span>--> 6
注意:如果一个函数的参数列表是空的话,调用该函数时必须像C语言一样,在后面加上(),表明将要调用该函数。如:
function print_test() print("hello world") end print_test() --print_test --这样不加括号的调用不能被正确编译注意:如果一个函数只有一个参数,并且这个参数是字符串或是表结构的话,在调用该函数时,可以不用加括号。如:
print "hello world" a = {1,2,3,4} print(a) print a --不可以是代表表结构的变量,不能编译通过 print {1, 2, 3, 4} -- 必须是这种参数直接为表结构的方式另外,函数的实参可以传入随意个数,并不影响函数的调用,但是能否执行成功,需要函数自己做检查。如果实参的个数多于形参,多余的实参会被舍弃;如果实参的个数少于形参,多余的形参会被置为nil,如:
function f(a, b) return a, b end f(3) -- a = 3, b = nil f(3, 4) -- a = 3, b = 4 f(3, 4, 5) -- a = 3, b = 4, 5被舍弃
function f() return 3, 4 end a = f() print(a)<span style="white-space:pre"> </span>-- a = 3, 4被丢弃 a, b = f() print(a, b)<span style="white-space:pre"> </span>-- a = 3, b = 4 a, b, c =f() print(a, b, c) -- a = 3, b = 4, c = nil
function f() return 3, 4 end a, b = f() print(a, b) -- 3, 4 a, b = f(), 20 print(a, b) -- 3, 20 a, b, c = 30, f(), 20 print(a, b, c) -- 30, 3, 20函数在作为函数参数、表元素时,也是同样的。如:
function f() return 3, 4 end print(1, f()) --> 1, 3, 4 print(f()) --> 3, 4 print(f(), 1) --> 3, 1 print(f() .. "x") --> 3x a = {1, f()} print(a[1], a[2], a[3], a[4]) -->1, 3, 4, nil a = {f(), 2} print(a[1], a[2], a[3], a[4]) -->3, 2, nil, nil a = {f()} print(a[1], a[2], a[3], a[4]) -->3, 4, nil, nil
function f() return 3, 4 end function t() return f() end print(t()) -->3, 4
function f() return 3, 4 end print((f())) -->3
unpack()函数是lua中的一个特殊函数,它接收一个数组变量,返回数组的所有元素,该函数多用来协助实现可变参数的函数。在5.2版本以前的lua中,该函数作为一个全局函数存在的,可以随意调用。在5.2以后的版本中,该函数被移动到table库下面了,需要使用table.unpack()调用。如:
f =string.find a = {"hello","ll"} print(f(table.unpack(a))) --> 3 4
Lua 函数可以接受可变数目的参数,和 C 语言类似在函数参数列表中使用三点(...) 表示函数有可变的参数。
5.1版本之前的Lua 将函数的参数放在一个叫 arg 的表中,除了参数以外,arg表中还有一个域 n 表示参数的个数。但是在5.2版本之后的lua就不会帮助组织arg数组了,必须由开发者自己组织。如:
function average(...) result = 0 local arg={...} --5.2以后的lua版本必须显示指明,否则arg为nil,而且没有了表示个数的n变量 for i,v in ipairs(arg) do result = result + v end print("总共传入 " .. #arg .. " 个数") print(arg[n]) return result/#arg end print("平均值为",average(10,5,3,4,5,6))
Lua 中的函数是带有词法定界(lexical scoping)的第一类值(first-class values)。
第一类值指:在 Lua 中函数和其他值(数值、字符串)一样,函数可以被存放在变量中,也可以存放在表中,可以作为函数的参数,还可以作为函数的返回值。
词法定界指:被嵌套的函数可以访问他外部函数中的变量。这一特性给 Lua 提供了 强大的编程能力。
在lua中,函数可以是匿名的,如:
a = function (x) return x end print(a(5))这两句中将a定义成一个function类型的变量,它的值为一个函数。在某些方面,a的作用,与C语言中的函数指针比较类似。
这也是lua中最原始的function类型变量的定义方式,不过,我们常常写成下面的这种方式:
function a(x) return x end print(a(5))这种方式与其他语言对函数的定义比较相似,更容易接受。
lua中函数还可以作为另一个函数的参数使用,这也与C语言中的函数指针类似。唯一的不同是,由于lua支持词法定界,可以在传参时直接定意思匿名函数作为实参传递。如:
table.sort(network,function (a,b) return (a.name > b.name) end)
sort函数对network数组进行排列,排列的标准以第二个参数为准。第二个参数为函数,提供了排序的参考标准。这个地方并没有像C那样传递函数指针,而是直接定义了一个匿名函数进行传递。
闭合函数:
闭合函数也称为闭包。
当一个函数内部嵌套另一个函数定义时,内部的函数体可以访问外部的函数的局部变量,这种特征我们称作词法定界。
由于lua支持词法定界和第一类值,lua的函数,可以访问本来不属于它的局部变量,并维持这个变量。lua的函数与它可以访问的局部变量,就组成了一个闭合函数。对于外部函数中的局部变量,闭合函数会自动维持这个值。如果不再次调用外部函数,则闭合函数中外部的局部变量不会被再次初始化。如:
function count() local i = 0; return function() i = i + 1; return i; end end a = count(); print(a()); -->1 print(a()); -->2 print(a()); -->3 a = count() print(a()); -->1
非全局函数:
lua中,非全局函数的定义就跟普通变量的定义一样,如:
local a a = function (x) return x end print(a(3)) --> 3它的定义方式等价于以下方式:
local function a(x) return x end print(a(3)) --> 3
当一个函数的最后一个动作,是调用另一个函数时,这样的函数调用,就属于尾调用。类似于C语言的goto语句。
使用了尾调用的函数会在结束时直接进行函数调用,因为调用后不用再对本函数进行任何动作,所以不用在堆栈中保留任何本函数的信息。这样的函数可以支持无限深度的递归类函数。如:
function foo(n) if n > 0 then return foo(n - 1); else return "end"; end end print(foo(9999999))这个函数在很短的时间内,就会打印“end”字符串。
注意:如果在return语句中,包含函数调用和其他表达式,或者是函数调用结束后,才进行return的话,就不是真正的尾调用,它在每次函数调用之前,都需要在堆栈中保存本函数的信息。如果频繁的进行调用,会产生堆栈错误。如:
function foo(n) if n > 0 then return foo(n - 1) + 1; else return "end"; end end print(foo(9999999))
或者是:
function foo(n) if n > 0 then foo(n - 1) return ; else return "end"; end end