闭包 Closures
1.闭包表达式
闭包表达式是一种利用简单语法构建内联包的方式,提供一些语法优化,使得闭包代码变得更加简单明了
1.1sort函数
Swift标准库提供了sort函数,将已知类型数组中的值进行排序,返回一个与原数组大小相等但元素已正确排序的数组
sort函数需要传入两个参数:
1.已知类型的数组
2.传入两个跟数组相同类型参数的闭包函数,并返回一个布尔值告诉sort函数排序结束后传入的第一个参数排在第二个参数的前面还是后面,如果第一个参数值出现在第二个参数值前面,排序闭包函数需要返回true,否则返回false
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
该例子对String类型的数组进行排序,因此该排序闭包函数类型为 (String, String) -> Bool
提供排序闭包函数的另一种方式是写一个符合其类型要求的普通函数,并将其作为sort函数的第二个参数传入
func backwards(s1: String, s2: String) -> Bool {
return s1 > s2
}
var reversed = sort(names, backwards)
// reversed is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
1.2闭包表达式语法
闭包表达式一般形式,可以使用常量、变量和inout类型作为参数,不提供默认值,也可以在参数列表后面使用可变参数。元组也可以作为参数和返回值
{ (parameters) -> return type in
statements
}
// backwards函数对应的闭包表达式版本,闭包的函数体部分由关键字 in 引入
// 该关键字表示闭包的参数和返回值类型定义已经完成,闭包函数体开始
reversed = sort(names, { (s1: String, s2: String) -> Bool in
return s1 > s2
})
// 简写形式
reversed = sort(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )
1.3根据上下文推断类型
因为排序闭包函数是作为sort函数的参数进行传入,Swift可以判断其参数和返回值的类型
reversed = sort(names, { s1, s2 in return s1 > s2 } )
1.4单行表达式闭包隐式返回
单行表达式闭包可以通过隐藏return关键字来隐式返回单行表达式的结果
reversed = sort(names, { s1, s2 in s1 > s2 } )
1.5参数名称缩写
Swift自动为内联函数提供了参数名称缩写功能,可直接通过 $0,$1,$2 来顺序调用闭包的参数。如果您在闭包表达式中使用参数名称缩写,可以在闭包参数列表中省略对其的定义,并且对应参数名称缩写的类型会通过函数类型进行推断。 in关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成
reversed = sort(names, { $0 > $1 } )
1.6运算符函数
Swift 的String类型定义了关于大于号 (>) 的字符串实现,其作为一个函数接受两个String类型的参数并返回Bool类型的值。 而这正好与sort函数的第二个参数需要的函数类型相符合。 因此可以简单地传递一个大于号,Swift可以自动推断出您想使用大于号的字符串函数实现
reversed = sort(names, >)
2.尾随闭包
如果需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。如果函数只需要闭包表达式一个参数,当使用尾随闭包时,甚至可以把()省略掉。
func someFunctionThatTakesAClosure(closure: () -> ()) {
// function body goes here
}
// 以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure({
// closure's body goes here
})
// 以下是使用尾随闭包进行函数调用
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}
//在上例中作为sort函数参数的字符串排序闭包可以改写为:
reversed = sort(names) { $0 > $1 }
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map {
(var number) -> String in
var output = ""
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
}
// strings is inferred to be of type String[]
// its value is ["OneSix", "FiveEight", "FiveOneZero"]
3.值捕获
闭包可以在其定义的上下文中捕获常量或变量。即使定义这些常量和变量的原域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。Swift最简单的闭包形式是嵌套函数,也就是定义在其他函数的函数体内的函数。 嵌套函数可以捕获其外部函数所有的参数以及定义的常量和变量。
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
let incrementByTen = makeIncrementor(forIncrement: 10)
incrementByTen()
// returns a value of 10
incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30
let incrementBySeven = makeIncrementor(forIncrement: 7)
incrementBySeven()
// returns a value of 7
incrementByTen()
// returns a value of 40
4.闭包是引用类型
无论将函数/闭包赋值给一个常量还是变量,实际都是将常量/变量的值设置为对应函数/闭包的引用,如果将闭包赋给了两个不同的常量/变量,两个值都会指向同一个闭包
let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
// returns a value of 50