闭包
例子中使用sort函数
sort需要传入一个闭包,采用相同类型的数组的内容的两个参数,并返回一个布尔值来表示是否将第一个值在排序时放到第二个值的前面或是后面。如果第一个值应该出现第二个值之前,闭包需要返回true,否则返回false。
该例子对一个 String 类型的数组进行排序,因此排序闭包需为 (String, String) -> Bool 类型的函数
闭包简介
闭包表达式语法有如下一般形式:
{ (parameters) -> returnType in
statements
}
闭包表达式语法可以使用常量、变量和 inout 类型作为参数,但不提供默认值。 也可以在参数列表的最后使用可变参数。元组也可以作为参数和返回值。
普通函数做闭包
func backwards(s1: String, s2: String) -> Bool {
return s1 > s2
}
//let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
var reversed = names.sort(backwards)
// reversed is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
使用闭包表达式版本
reversed = names.sort({ (s1: String, s2: String) -> Bool in
return s1 > s2
})
//简化为一行
reversed = names.sort({ (s1: String, s2: String) -> Bool in return s1 > s2 } )
根据上下文推断类型
因为排序闭包是作为函数的参数进行传入的,Swift可以推断其参数和返回值的类型。 sort 期望参数是类型为 (String, String) -> Bool 的函数,因此实际上 String, String 和 Bool 类型并不需要作为闭包表达式定义中的一部分。 因为所有的类型都可以被正确推断,返回箭头 (->) 和 围绕在参数周围的括号也可以被省略:
reversed = names.sort({ s1, s2 in return s1 > s2 } )
单行闭包表达式隐藏return
reversed = names.sort( { s1, s2 in s1 > s2 } )
sort 函数的参数函数类型明确了闭包必须返回一个 Bool 类型值。 因为闭包函数体只包含了一个单一表达式 (s1 > s2),该表达式返回 Bool 类型值,因此这里没有歧义,return关键字可以省略
参数名简写
如果您在闭包表达式中使用参数名称简写,您可以在闭包参数列表中省略对其的定义,并且对应参数名称简写的类型会通过函数类型进行推断。 in 关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成:
reversed = names.sort({ $0 > $1 } )
在这个例子中,$0 和 $1 表示闭包中第一个和第二个 String 类型的参数。
运算符函数
Swift的 String 类型定义了关于大于号 (>) 的字符串实现,让其作为一个函数接受两个 String 类型的参数并返回 Bool 类型的值。 而这正好与 sort 函数的第二个参数需要的函数类型相符合。 因此,您可以简单地传递一个大于号,Swift可以自动推断出您想使用大于号的字符串函数实现:
reversed = names.sort( >)
Trailing 闭包
如果您需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用 trailing 闭包来增强函数的可读性
reversed = names.sort(){ $0 > $1 }//闭包作为最后一个参数
reversed = names.sort{ $0 > $1 }//因为只有一个参数所以省略了()
捕获值
闭包可以根据环境上下文捕获到定义的常量和变量。闭包可以引用和修改这些捕获到的常量和变量,
就算在原来的范围内定义为常量或者变量已经不再存在。
在Swift中闭包的最简单形式是嵌套函数。
func increment(amount: Int) -> (() -> Int) {
var total = 0
func incrementAmount() -> Int {
total += amount // total是外部函数体内的变量,这里是可以捕获到的
return total
}
return incrementAmount // 返回的是一个嵌套函数(闭包)
}
// 闭包是引用类型,所以incrementByTen声明为常量也可以修改total
let incrementByTen = increment(amount: 10)
incrementByTen() // return 10,incrementByTen是一个闭包
// 这里是没有改变对increment的引用,所以会保存之前的值
incrementByTen() // return 20
incrementByTen() // return 30
let incrementByOne = increment(amount: 1)
incrementByOne() // return 1
incrementByOne() // return 2
incrementByTen() // return 40
incrementByOne() // return 3