基础知识:
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)) --> 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) -- a = 3, 4被丢弃
a, b = f()
print(a, b) -- 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