UH2S1L7——函数

函数

在Lua中,函数也是一种变量类型,而Lua的函数声明不需要指定返回值的类型

1
2
3
function 函数名(参数列表)
函数代码块
end
1
2
3
函数名 = function(参数列表)
函数代码块
end

要注意,由于Lua是解释型语言,解释器从上到下执行代码,因此调用函数不能在函数声明之前,否则会报错

无参无返回值

1
2
3
4
5
6
7
8
9
10
print("**********无参无返回值************")
function F1()
print("F1函数")
end
F1()

F2 = function()
print("F2函数")
end
F2()
1
2
3
**********无参无返回值************
F1函数
F2函数

通过第二种写法可以发现,在Lua中函数是一种变量类型,用起来就像是C#中的委托那样

有参数

Lua的函数声明中,参数列表是不需要写清楚参数的类型的,
因此,调用函数时,可以传入各种类型的值
(当然内部的逻辑不一定能允许你瞎写,就像下面的函数传入nil​或者boolean​就会报错)

1
2
3
4
5
6
print("**********有参数************")
function F3(a)
print("参数:" .. a)
end
F3(1)
F3("123")
1
2
3
**********有参数************
参数:1
参数:123

在Lua中,对一个函数不传入参数或者传入多余的参数这个行为本身不会报错(即传入参数个数与声明参数个数不匹配)
前者会让空着的参数为nil​,后者会丢弃多余的参数

1
2
3
4
5
function FTest(a)
print(a)
end
FTest()
FTest(1, 2, 3)
1
2
nil
1

有返回值

在函数声明时,无需声明返回值类型,而要返回值时,直接return​一个值即可

1
2
3
4
5
6
print("**********有返回值************")
function F4(a)
return a
end
temp = F4("123")
print(temp)
1
2
**********有返回值************
123

Lua的return​可以返回多个值,用逗号分隔即可,需要多个变量去接受它,
如果没有足够的变量接收值,则多余的返回值会被丢弃,但是对应位置的值仍然可以接收到
当然,如果有过多的变量去接收这个值,则多出的变量接收不到任何值
接收返回值的变量数量与函数中实际返回的值数量不一致,不会导致报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
print("**********有返回值************")
function F4(a)
return a, "456", true
end
temp = F4("123")
print(temp)
temp1, temp2, temp3 = F4("123")
print(temp1)
print(temp2)
print(temp3)
tempA, tempB, tempC, tempD = F4("******")
print(tempA)
print(tempB)
print(tempC)
print(tempD)
1
2
3
4
5
6
7
8
9
**********有返回值************
123
123
456
true
******
456
true
nil

函数的类型

Lua中的函数作为变量最直观的证明就是直接用type()​来输出查看返回的值

1
2
3
4
5
print("**********函数类型************")
F5 = function()
print("123")
end
print(type(F5))
1
2
**********函数类型************
function

可见函数在Lua中就是一种变量类型

函数重载

函数重载就是函数名相同但参数类型数量不同,返回值也不同的函数可以共同存在
Lua不支持函数重载! ,如果在之前先后声明了重名的函数 (这个行为本身不会报错!需要注意) ,则调用函数一定会调用最后声明的那个函数

1
2
3
4
5
6
7
8
9
10
11
print("**********验证函数重载************")
function F6()
print("我是无参的")
end

function F6(str)
print(str)
end

F6()
F6("我是有参的")
1
2
3
**********验证函数重载************
nil
我是有参的

如果支持函数重载,这里的返回应当分别是我是无参的​和我是有参的​,
但明显,这段代码两次调用的都是后来声明的函数,可见,Lua不支持函数重载

变长函数

不定参数在参数列表内用...​​,需要一个表来接收它

1
2
3
4
5
6
7
8
print("**********变长参数************")
function F7( ... )
arg = { ... }
for i = 1, #arg do
print(arg[i])
end
end
F7(1, "2", 3, true, 5, 6)
1
2
3
4
5
6
7
**********变长参数************
1
2
3
true
5
6

和C#一样,参数列表中局部参数与不定参数声明可以共存,不定参数必须要在参数列表最后一位

1
2
3
4
5
6
7
8
9
10
function FTest2(a, b, ...)
print(a)
print(b)
print(...)
arg = { ... }
for i = 1, #arg do
print(arg[i])
end
end
FTest2(1, "2", 3, true, 5, 6)
1
2
3
4
5
6
7
1
2
3 true 5 6
3
true
5
6

可以看到a = 1​,b = 2​,...​包括3, true, 5, 6

函数嵌套

函数作为lua中的一种变量类型,是可以在函数中返回的,
因此你可以直接返回一个函数的声明给外部(如果直接返回函数声明,则该函数声明不可以命名)

1
2
3
4
5
6
7
8
9
print("**********函数嵌套************")
function F8()
return function()
print(123)
end
end

f9 = F8()
f9()
1
2
**********函数嵌套************
123

命名的函数也可以返回,需要先声明并赋值后再返回

1
2
3
4
5
6
7
8
9
function Fa()
Fb = function()
print(123)
end
return Fb
end

fb = Fa()
fb()
1
123

甚至可以在函数里嵌套声明与外层函数重名的函数(不要这么做)

1
2
3
4
5
6
7
8
9
function Fa()
Fa = function()
print(123)
end
return Fa
end

fa = Fa()
fa()
1
123

函数嵌套涉及的闭包

由于可以嵌套声明函数,以及返回函数,因此会出现函数局部变量生命周期改变的情况,也就是闭包

1
2
3
4
5
6
7
8
function F9(x)
return function(y)
return x + y
end
end

f10 = F9(10)
print(f10(5))
1
15

原本F9​的参数也就是局部变量x​在执行完F9​的代码后生命周期就结束了,但是F9​返回的函数仍然在使用x
这就导致局部变量x​的生命周期函数被改变,x​会在f10​存储的函数里继续使用