闭包是完成特定任务的互相分离的功能组。函数是闭包的特殊情况,可看成有名字的闭包。但是一般闭包其语法更加紧凑、轻量。闭包与函数结构类似,但是省去命名和函数声明,因此闭包更容易以函数参数和返回值的形式传递。
以一个数组排序为例。
import Cocoa
let volunteerCounts = [1,4,35,31,3,58,88]
func sortAscending(_ i: Int, _ j: Int) -> Bool {
return i < j
}
let volunteersSorted = volunteerCounts.sorted(by: sortAscending)
其中,sorted(by:)接受一个参数:一个描述如何排序的闭包。这个闭包接受两个参数,其类型必须和数组元素的类型匹配,并返回布尔值。通过比较两个参数会生成返回值,表示第一个参数是否排在第二个前面。此处,sorted(by:)的函数类型为((Int,Int) -> Bool -> [Int] )。
一、闭包表达式
用闭包表达式实现 更加简洁的写法。闭包表达式的一般形式如下:
{(parameters)-> return types in
//代码
}
闭包表达式写在花括号中。关键字in用来分隔闭包的参数、返回值与闭包体内的语句。
上述代码的闭包表达式重构写法:
import Cocoa
let volunteerCounts = [1,4,35,31,3,58,88]
let volunteersSorted = volunteerCounts.sorted(by:{
(_ i: Int, _ j: Int) -> Bool in
return i < j
})
同时,闭包可以利用Swift的类型推断系统,此处可以通过去除类型信息来进一步简化闭包。
import Cocoa
let volunteerCounts = [1,4,35,31,3,58,88]
let volunteersSorted = volunteerCounts.sorted(by: { i, j in i < j })
代码改动了三处。其一,移除了参数和返回值的类型信息。返回值类型可以移除是因为编译器知道检查i < j是否成立会返回布尔值true 或false。其二,把整个闭包表达式放到了同一行。其三,移除了关键字return。不是所有的闭包语句都可以省略关键字,这里可以是因为只有一个表达式。否则显式的return是必需的。
其他简化:
快捷参数法: let volunteersSorted = volunteerCounts.sorted(by:{ $0 < $1})
尾部闭包语法:let volunteersSorted = volunteerCounts.sorted{ $0 < $1}
二、函数作为返回值
每个函数都有其参数和返回值类型的函数类型。函数类型常用来判断什么样的闭包能满足给定的参数类型或需要返回什么样的函数。
函数可以返回其他函数作为返回值。
import Cocoa
let volunteerCounts = [1,4,35,31,3,58,88]
let volunteersSorted = volunteerCounts.sorted{ $0 < $1}
func makeTownGrand() -> (Int, Int) -> Int {
func buildRoads(byAddingLights lights: Int,
toExistingLights existingLights: Int) -> Int{
return lights + existingLights
}
return buildRoads
}
三、函数作为参数
函数也可以作为其他函数的参数。
import Cocoa
let volunteerCounts = [1,4,35,31,3,58,88]
let volunteersSorted = volunteerCounts.sorted{ $0 < $1}
func makeTownGrand(withBudget budget: Int,
condition: (Int) -> Bool) -> ((Int, Int) -> Int)? {
if condition(budget) {
func buildRoads (byAddingLights lights: Int,
toExistingLights existingLights: Int) -> Int{
return lights + existingLights
}
return buildRoads
}else{
return nil
}
}
func evaluate(budget: Int) -> Bool {
return budget > 10000
}
var stoplights = 4
if let townPlanByAddingLightsToExistingLights = makeTownGrand(withBudget: 1000, condition: evaluate){
stoplights = townPlanByAddingLightsToExistingLights(4, stoplights)
}
四、引用类型
闭包是引用类型。当把函数赋给常量或变量时,实际上是在让这个常量或变量指向这个函数。而并没有为这个函数创建新的副本。