标签:
闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift中的闭包与C和Objective-C中的代码块(blocks)以及其他一些编程语言中的Lambda函数比较相似。在本章中所讲的函数其实就是特殊的闭包。本节主要讲解关于闭包的基本使用。
闭包表达式是一种利用简洁语法构建内联(内联类似与C语言中的宏定义)闭包的方式。以下这个代码是对两个字符串的比较。
import Foundation
//判断两个字符串的大小
func compare(s1: String, s2: String) -> Bool {
return s1 > s2
}
let str1="Hello"
let str2="Swift"
if compare(str1, s2: str2) {
print("str1大于str2")
}else{
print("str1小于str2")
}
运行结果如下:
str1小于str2
在此代码中,当调用函数compare()时,会将str1和str2传递到给函数在定义时的参数s1,s2中,然后进行比较。在此代码中可以看到,在compare()函数中执行了一行代码,就是判断并返回,显的此函数相当冗长。此时就可以使用闭包表达式使用代码变得更好。首先,来看一下闭包表达式(闭包函数)的语法形式。
{(参数列表)->返回值类型 in
语句
}
其中,参数可以是常量、变量和输入-输出参数,但没有默认值。开发者也可以在参数列表的最后使用可变参数。而元组也可以作为参数和返回值。关键字in表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始。
1.无参形式的闭包表达式
无参形式的闭包表达式语法形式如下:
{()->返回值类型 in
语句
}
它定义的语法形式如下:
let/var 闭包表达式常量名称/闭包表达式变量名称/=无参形式的闭包表达式
它调用的语法形式如下:
闭包表达式常量名称/闭包表达式变量名称()
【示例7-27】以下将使用闭包表达式实现字符串"aaaa"的输出。代码如下:
import Foundation
//输出字符串"aaaa"
var str={() in
print("aaaa")
}
str() //调用的调用形式
运行结果如下:
aaaa
2.具有参数的闭包表达式
具有参数的闭包表达式有两种形式一种是最常用的只有一个参数的闭包表达式;一种是具有多个参数的闭包表达式。以下是对这两种具有参数的闭包表达式的详细讲解。
(1)具有一个参数的闭包表达式
具有一个参数的闭包表达式的语法形式如下:
{(参数名:数据类型)->返回值类型 in
语句
}
它定义的语法形式如下:
let/var 闭包表达式常量名称/闭包表达式变量名称/=具有一个参数的闭包表达式
它的调用形式如下:
闭包表达式常量名称/闭包表达式变量名称()
【示例7-28】以下将使用闭包表达式输出指定字符串。代码如下:
import Foundation
//输出指定的字符串
var str={(str:String) in
print(str)
}
str("Hello")
运行结果如下:
Hello
(2)具有多个参数的闭包表达式
具有多个参数的闭包表达式的语法形式如下:
{(参数名1:数据类型,参数名2:数据类型,…)->返回值类型 in
语句
}
它定义的语法形式如下:
let/var 闭包表达式常量名称/闭包表达式变量名称/=具有多个参数的闭包表达式
它的调用形式如下:
闭包表达式常量名称/闭包表达式变量名称()
【示例7-29】使用闭包实现对两个任意数的求和计算,代码如下:
import Foundation
//实现求两个数的和
var reversed = {(s1: Int, s2: Int) -> Int in
var sum=s1+s2
return sum
}
print(reversed(10,20))
运行结果如下:
30
其实闭包表达式最长用在其他的函数中,并不是单独的去使用它。
【示例7-30】以下代码将闭包表达式作为函数的一部分,来实现在判断在数组中是否有大于500或者40的元素。代码如下:
import Foundation
//定义函数
func copare(arr:[Int],value:Int,cb:(Num:Int,Value:Int)->Bool)->Bool{
//遍历数组
for item in arr{
//判断闭是否为真
if(cb(Num: item,Value: value)){
return true
}
}
return false
}
var array = [20,80,100,50,20]
//使用闭包判断是否在数组中有大于500的元素
var v1=copare(array,value: 500,cb: {(num:Int,value:Int)->Bool in
return num>value
})
//判断结果并输出·
if v1==true {
print("数组array中有比500大的元素")
}else{
print("数组array中没有比500大的元素")
}
//使用闭包判断是否在数组中有大于40的元素
var v2=copare(array,value: 40,cb: {(num:Int,value:Int)->Bool in
return num>value
})
//判断结果并输出
if v2==true {
print("数组array中有比40大的元素")
}else{
print("数组array中没有比40大的元素")
}
在此代码中,当调用copare()函数时,会将参数array、40以及闭包表达式传递到函数定义的参数中,在copare()函数中,遍历数组中元素的时候,又会去调用闭包表达式。运行结果如下:
数组array中没有比500大的元素
数组array中有比40大的元素
在使用闭包表达式时需要注意以下几点(以下都是以示例7-30来说明的):
1.推断类型
copare()函数的第三个参数是闭包表达式,它的类型为(num:Int,value:Int)->Bool,由于Swift可以推断其参数和返回值的类型,所以->和围绕在参数周围的括号可以省略,如以下的代码:
var v1=copare(array,value:500,cb:{(num,value) in
return num>value
})
2.省略return
单行表达式闭包可以通过隐藏return关键字来隐式返回单行表达式的结果,可以将上面的例子进行修改:
var v1=copare(array,value:500,cb:{(num,value) in
num>value
})
3.简写参数名
Swift为内联函数提供了参数名缩写功能,开发者可以通过$0、$1、$2来顺序的调用闭包的参数。如果在闭包表达式中使用参数名称缩写,可以在闭包参数列表中省略对其的定义,并且对应参数名称缩写的类型会通过函数类型进行推断。in关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成,将上面的例子进行修改:
var v1=copare(array, value:500,cb: {
$0 > $1
})
4.写在一行
当闭包的函数体部分很短时可以将其写在一行上面,如以下代码:
var v1=copare(array,value: 500,cb: {$0 > $1})
5.运算符函数
在Swift中String类型定义了关于大于号(>)的字符串实现,其作为一个函数接受两个String类型的参数并返回Bool类型的值。而这正好与以上代码sort函数的第二个参数需要的函数类型相符合。 因此,可以简单地传递一个大于号,Swift可以自动推断出您想使用大于号的字符串函数实现:
var v1=copare(array,value:500,cb:>)
在Swift 1.2中使用闭包表达式需要注意以下三点:
q 有单返回语句的闭包,现在类型检查时以单表达式闭包处理。
q 匿名的且含有非空返回类型的单表达式,现在可以用在void上下文中。
q 多表达式的闭包类型的情况,可能无法被类型推断出来。
如果开发者需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用Trailing闭包,它可以增强函数的可读性。Trailing闭包的一般形式如下:
func someFunctionThatTakesAClosure(closure: () -> ()) {
//函数主体部分
}
//以下不是使用trailing闭包进行的函数调用
someFunctionThatTakesAClosure({
//闭包主体部分
})
//以下是使用trailing闭包进行的函数调用
someFunctionThatTakesAClosure() {
//闭包主体部分
}
注意:trailing闭包是一个写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。示例7-30中代码也可以写为Trailing闭包,代码如下:
import Foundation
func copare(arr:[Int],value:Int,cb:(Num:Int,Value:Int)->Bool)->Bool{
for item in arr{
if(cb(Num: item,Value: value)){
return true
}
}
return false
}
var array = [20,80,100,50,20]
var v1=copare(array,value:500) {(num:Int,value:Int)->Bool in
return num>value
}
if v1==true {
print("数组array中有比500大的元素")
}else{
print("数组array中没有比500大的元素")
}
…
Trailing闭包一般使用在当闭包很长以至于不能在一行进行编写的代码中。如以下的例子就使用了Trailing闭包,实现将数字改为英文的功能。代码如下:
import Foundation
//创建字典
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
//创建数组
let numbers = [521,52,1,13,14]
//以下是使用trailing闭包进行的函数调用,实现将数字转为英文
let strings = numbers.map {
(var number) -> String in
var output = ""
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
}
//遍历并输出
for index in strings{
print(index)
}
运行结果如下所示:
FiveTwoOne
FiveTwo
One
OneThree
OneFour
注意:在此代码中使用到了函数map(),它的功能是返回一个新的序列。其语法形式如下:
map(序列,闭包表达式)
其中,如果闭包表达式适用于序列中的所有元素,就会返回一个新的序列。但是在本示例中由于闭包中的内容比较多,就将它使用了Trailing闭包的形式。
闭包可以在其定义的上下文中捕获常量或变量。以下就使用incrementor()函数从上下文种对值runningTotal和amount进行捕获。代码如下:
import Foundation
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
//定义函数incrementor(),实现runningTotal的增加
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
//赋值
var a = makeIncrementor(forIncrement: 10)
//输出
print("输出a的增量")
print(a())
print(a())
print(a())
var b = makeIncrementor(forIncrement: 5)
//赋值,输出
print("输出b的增量")
print(b())
print(b())
print(b())
运行结果如下所示:
输出a的增量
10
20
30
输出b的增量
5
10
15
本文选自:Swift2.0语言快速入门v3.0 大学霸内部资料,转载请注明出处,尊重技术尊重IT人!
标签:
原文地址:http://my.oschina.net/u/1585857/blog/480714