感觉学习语言的话,函数是个重头戏。来看一下Lua的函数是神马样纸的东东!
一.简单的函数例子
--一个简单的函数:阶乘
function factorial(num)
if num == 0 then
return 1
else
return num * factorial(num - 1)
end
end
恩,这就是个函数。function关键字,说明这是个函数,然后是函数名,后面跟的是参数列表,使用括号括起来。函数的结尾需要一个end关键字,表明函数结束了。
下面看以下怎么调用:
--一个简单的函数:阶乘
function factorial(num)
if num == 0 then
return 1
else
return num * factorial(num - 1)
end
end
--调用函数的例子:输入一个数字,求其阶乘
line = io.read()
n = tonumber(line)
if n == nil then
print("input is not a valid num")
else
print(factorial(n))
end
结果:
5
120
请按任意键继续. . .
120
请按任意键继续. . .
调用函数时,有几个地方需要注意一下:
1.当函数后面只有一个参数,并且这个参数是字符串或table构造式时,可以省略括号。
比如:
--函数后面只有一个参数,且为字符串
print "hello world"
--函数后面只有一个参数,且为table构造式
print {x = 10, y = 20}
结果:
hello world
table: 003BEC40
请按任意键继续. . .
table: 003BEC40
请按任意键继续. . .
2.调用函数时,给出参数如果和要求不符时,不会报错,处理策略采用:参数多了的舍弃,少了的为nil
function myprint(a, b, c)
print(a, b, c)
end
--正常调用
myprint(1, 2, 3)
--参数多了
myprint(1, 2, 3, 4)
--参数不足
myprint(1, 2)
结果:
1 2 3
1 2 3
1 2 nil
请按任意键继续. . .
1 2 3
1 2 nil
请按任意键继续. . .
二.多重返回值
记得刚学C语言的时候,还不会神马通过指针参数返回参数的方法,当时就特别纠结,要是有多个返回值得肿么办,不过慢慢就习惯了,通过结构体啦,或者指针或者引用实参传递多个参数了。没想到Lua竟然支持多重返回值!!!真的是灰常强大的设定!
一个例子:
--赶脚灰常牛的特性,多个返回值
--一个接受一个table的函数,返回最大元素以及该元素的位置
function maxinum(a)
local index = 1
local max = a[index]
for i, val in ipairs(a) do
if val > max then
max = val
index = i
end
end
return max, index
end
--测试
a = {1, 2, 3, 10, 4, 8, 5, 7}
print(maxinum(a))
结果:
10 4
请按任意键继续. . .
请按任意键继续. . .
当然,多重返回值也不是任何时候都触发的,Lua会根据不同的情况进行调整。在以下四种情况时,会触发多重赋值:
1.多重赋值
2.函数调用传入实参列表
3.table构造式
4.return语句
针对不同的情况,看几个例子
1.多重赋值
--多重返回值demo
function func()
return 1, 2, 3
end
--正常的多重赋值,按照顺序进行多重赋值,返回值个数多了的舍去,少了的取nil
a , b, c = func()
print(a, b, c)
--若函数是多重赋值的最后一个或者唯一一个表达式,那么会尽可能的保留其返回值
a, b, c = 0, func()
print(a, b, c)
--若函数不是最后一个的话,则只产生一个返回值
a, b, c = func(), 0
print(a, b, c)
结果:
1 2 3
0 1 2
1 0 nil
请按任意键继续. . .
0 1 2
1 0 nil
请按任意键继续. . .
2.函数调用传入实参列表
--多重返回值demo
function func()
return 1, 2, 3
end
--接受固定参数的myprint()
function myprint(a, b, c)
print(a, b, c)
end
--当仅有或者为最后一个形参时,会尽可能保留其返回值
print(func())
--myprint仅接受三个参数
myprint(0, func())
--函数表达式为不为最后一个时,仅保留一个返回值
print(func(), 1)
结果:
1 2 3
0 1 2
1 1
请按任意键继续. . .
0 1 2
1 1
请按任意键继续. . .
如果函数出现在一个表达式中,lua会自动将返回值个数调整为1个,即第一个。
--多重返回值demo
function func()
return 1, 2, 3
end
--当有()括起函数时,即形成了一个表达式,不管函数返回几个值,仅取一个值
print((func()))
结果:
1
请按任意键继续. . .
3.table构造式
table比较强大,类似vector,想装多少装多少,所以,我们在table构造式中返回的值都可以被其吸收。不过,这个行为也是和之前的一样,仅当只有一个函数作为构造实参时或者函数为最后一个构造实参时才有这种效果,否则又是仅返回一个值。
--多重返回值demo
function func()
return 1, 2, 3
end
--打印table中所有值的函数
function myprint(a)
for i, v in ipairs(a) do
print(v)
end
print("--------------------------------")
end
--当仅有一个或者是最后一个构造实参时
a = {func()}
myprint(a)
a = {0, func()}
myprint(a)
--当不是最后一个时,仅能返回一个值
a = {func(), 0}
myprint(a)
结果:
1
2
3
--------------------------------
0
1
2
3
--------------------------------
1
0
--------------------------------
请按任意键继续. . .
2
3
--------------------------------
0
1
2
3
--------------------------------
1
0
--------------------------------
请按任意键继续. . .
4.return语句
return语句本身要返回另一个函数的多个返回值,所以这个时候也支持多个函数的返回值。
例如:
--多重返回值demo
function func()
return 1, 2, 3
end
--return多个结果
function func2()
return 1,func()
end
function func3()
return func(),1
end
--func2调用func1,func1在最后会返回1,2,3
print(func2())
--func3调用func1,func1不在最后,仅返回1
print(func3())
结果:
1 1 2 3
1 1
请按任意键继续. . .
1 1
请按任意键继续. . .
三.变长参数
这个也是个棒棒哒的特性。使用...表示是变长参数。函数的形参设定为(...)即表明这个函数接受变长参数。一个例子:
--变长参数
--...表示变长参数,使用for循环遍历其中的内容
function add(...)
local sum = 0
for i, v in ipairs{...} do
sum = sum + v
end
return sum
end
--使用函数
print(add(1, 2, 3, 4, 5))
结果:
15
请按任意键继续. . .
请按任意键继续. . .
这里要注意的是,参数使用这个...表示,这里面将参数作为一个{...}数组来遍历。
关于...其实还是和多返回值的各种特性差不多:
--变长参数
--func
function func(...)
--直接打印这些参数
print(...)
--赋值(多了的舍去,少了的nil)
a, b = ...
print("a, b = ", a, b)
--使用(...)表示只取得第一个
return (...)
end
print(func(1,2,3))
结果:
1 2 3
a, b = 1 2
1
请按任意键继续. . .
a, b = 1 2
1
请按任意键继续. . .
关于可变参数,可以使用select关键字来取得第几个参数。
--关于可变参数的另一种遍历方式
function func(...)
for i = 1, select('#', ...) do
local arg = select(i, ...)
print(arg)
end
end
func(1, 2, 3, 4)
结果:
1
2
3
4
请按任意键继续. . .
2
3
4
请按任意键继续. . .
四.具名实参
具名实参,给我的赶脚就像一个结构体。我们传递一堆参数进来之后,经常忘记这个参数是干神马的,以至于最后调用的时候弄错了。所以,这时候,就像C语言那样,传递一个结构体进来,根据结构体的不同字段,进行操作就不会弄错了。
Lua中,实现的方法就是使用那个万能的table。具体的注意事项都在例子中写出:
--参数使用一个table的构造式,根据其中不同的字段获取其值
function Window(option)
--这里将参数的各个字段打印一遍
print(option.x or 0)--后面的为默认值,如果option.x为nil,则使用默认值
print(option.y or 0)
print(option.width or 800)
print(option.height or 600)
print("-------------------------------------------")
end
--当参数只有一个table的构造式时,可以省略括号
Window{x = 100, y = 200, width = 1000, height = 800}
--当有参数没给出时,会使用默认参数
Window{x = 100}
--顺序不一样也是可以的哈
Window{y = 100, width = 1000, x = 100, height = 800}
结果:
100
200
1000
800
-------------------------------------------
100
0
800
600
-------------------------------------------
100
100
1000
800
-------------------------------------------
请按任意键继续. . .
200
1000
800
-------------------------------------------
100
0
800
600
-------------------------------------------
100
100
1000
800
-------------------------------------------
请按任意键继续. . .
函数入门暂时就这些,还有一个unpack的函数,可以返回table中所有的内容,不过在我的电脑上一直没能试验成功,留个坑。