每天学一点Swift----闭包(二)
七.闭包表达式
1.调用闭包(使用闭包返回值):闭包的本质是功能更加灵活的代码块,因此完全可以将闭包赋值给变量(联想函数类型的变量)或直接调用闭包。举个栗子:
//定义一个闭包,并为闭包表达式的形参定义外部形参名,然后将闭包赋值给square变量
var square = {(value val : Int) -> Int in
return val * val
}
//这里和函数赋值给一个变量的实质内容是完全一样的,只是声明的写法不相同而已,对比与函数类型的变量,这里我称为闭包类型的变量
//使用闭包变量
println(square(5))//输出25
println(square(6))//输出36
//使用闭包表达式来定义闭包,并在闭包表达式后面增加圆括号来调用该闭包
//----更加牛逼了哈,,这样能调用多次吗??--答案是:no
var result = {(#base : Int, #exponent : Int) -> Int in
var result = 1
for i in exponent
{
result *= base
}
return result
}(3, 4)//使用圆括号调用闭包,计算3的4次方,则result得到是闭包的返回值
println(result)//输出81
2.从上面的程序中还可以看出,虽然闭包表达式支持为形参指定外部形参名,但这个外部形参名没有任何作用----程序调用闭包时依然不需要外部形参名,因此使用闭包表达式定义闭包是不需要指定外部形参名
3.完整的闭包表达式需要定义形参类型、返回值类型,但是Swift可以根据闭包表达式上下文推断形参类型、返回值类型,那么闭包表达式就可以省略形参类型、返回值类型。----如果闭包表达式省略了返回值类型,那就无须书写->符号;如果闭包表达式省略了形参类型,则也可以省略形参列表的圆括号。
4.举个栗子:
//使用闭包表达式,由于程序定义了square变量的类型,因此Swift可以推断闭包表达式的形参类型、返回值类型,因此可以省略闭包表达式的形参类型、返回值类型
var square : (Int) -> Int = {(val) in return val * val}
//省略形参类型后,也可以省略形参列表的圆括号,即上面的代码可以化简如下:
var square : (Int) -> Int = {val in return val * val}
println(square(5))// 25
println(square(6))// 36
//由于调用闭包表达式传入了4,3,因此Swift可以推断出闭包表达式的两个形参都是Int类型。程序将闭包表达式的返回值赋值给Int类型的变量,因此该闭包表达式的返回值是Int类型,只要Swift可以推断出闭包表达式的形参类型、返回值类型,闭包表达式即可省略形参类型、返回值类型。
var result : Int = {base, exponent in
var result = 1
for i in 1...exponent
{
result *= base
}
return result
}(4, 3)
print(result)// 64
5.省略return:如果闭包表达式的执行体只有一行代码,而且这行的返回值作为闭包表达式的返回值,那么Swift允许省略return关键字。举个栗子:
(1)//省略形参类型,省略返回值类型
//由于该闭包表达式只有一行代码,因此可以省略return关键字
var square : (Int) -> Int = (val in val * val)
print(square(5))//输出25
(2)//由于Swift无法推断闭包表达式的形参类型、返回值类型,因此不能省略形参类型、返回值类型
//由于闭包表达式只有一行代码,因此可以省略return关键字
var cube = {(val : Int) -> Int in val * val * val}
print(cube(5))//输出125
6.省略形参名:在闭包表达式可以省略形参类型、返回值类型的情况下,Swift甚至允许省略闭包表达式的形参名。如果闭包表达式省略了形参名,in关键字也就不需要了。此时,Swift允许闭包表达式通过$0, $1, $2....名字来引用第一个、第二个、第三个...形参。举个栗子:
//省略闭包表达式的形参类型、返回值类型、return关键字、形参名
//$0代表该闭包表达式中唯一的形参
var square : Int -> Int = {$0 * $0}
print(square(5))//输出25
//省略闭包表达式的形参类型、返回值类型、形参名,但不能省略return关键字
//$0代表该闭包表达式中的第一个形参,$1代表第二个形参
var result : Int = {
var result = 1
for i in 1...$1
{
result *= $0
}
return result
}(4, 3)
print(result)//输出64
7.尾随闭包
(1)比如有这样一个函数:func myFunc(val : Int, fn : (Int) -> Int){...}
因为函数的最后一个参数是函数类型的,所以,程序调用时既可以传入一个函数作为参数,也可以传入一个闭包作为参数,----再次证明,函数类型和闭包类型的实质是相同的。
(2)如果传入闭包作为参数,那么程序的调用方式为:
myFunc(20, {doSomethinf...}) ----花括号中的内容是闭包的执行体。
(3)从上面可以看出,如果传入类闭包作为参数,那么闭包的花括号就在函数的圆括号里面。
(4)尾随闭包则是一个提高可读性的写法----如果调用函数的***最后一个***参数是闭包,那么Swift将调用函数的圆括号提到闭包表达式的花括号之前,这种用法就被称为尾随闭包。
myFunc(20){doSomething...}----花括号中的内容是闭包的执行体。
*****看着跟定义函数的格式很像,用的时候一定要看仔细啊。。。。
(5)再次举个栗子:
//定义函数类型的形参,其中fn是(Int) -> Int类型的参数
func map(var #data : [Int], #fn : (Int) -> Int) -> [Int]
{
//遍历data数组中的每个元素,并用fn函数对data[i]进行计算
//然后将计算结果作为新的数组元素
for var i=0,len=data.count; i
{
data[i] = fn(data[i])
}
return data
}
var data = {3, 4, 9, 5, 8}
//调用3次map函数
//计算数组元素平方。尾随闭包,省略了形参类型、形参名、返回值类型、return关键字
var result1 = map(data:data){$0, $0}
//计算数组元素立方。尾随闭包,省略了形参类型、形参名、返回值类型、return关键字
var result2 = map(data:data){$0, $0, $0}
//计算数组元素阶乘。尾随闭包,省略了形参类型、形参名、返回值类型,不能省略return关键字
var result3 = map(data:data){
var result = 1;
for index in 2...$0
{
result *= index
}
return result
}
以上就是尾随闭包的用法。