闭包表达式(Closure Expressions)
嵌套函数 是一个在较复杂函数中方便进行命名和定义自包含代码模块的方式。当然,有时候撰写小巧的没有完整定义和命名的类函数结构也是很有用处的,尤其是在您处理一些函数并需要将另外一些函数作为该函数的参数时。
闭包表达式是一种利用简洁语法构建内联闭包的方式。 闭包表达式提供了一些语法优化,使得撰写闭包变得简单明了。 下面闭包表达式的例子通过使用几次迭代展示了sort(_:)
方法定义和语法优化的方式。 每一次迭代都用更简洁的方式描述了相同的功能。
sort 函数(The Sort Function)
Swift 标准库提供了名为sort
的函数,会根据您提供的用于排序的闭包函数将已知类型数组中的值进行排序。 一旦排序完成,sort(_:)
方法会返回一个与原数组大小相同,包含同类型元素且元素已正确排序的新数组。原数组不会被sort(_:)
方法修改。
下面的闭包表达式示例使用sort(_:)
方法对一个String类型的数组进行字母逆序排序,以下是初始数组值:
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
sort(_:)
方法需要传入两个参数:
- 已知类型的数组
- 闭包函数,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔类型值来表明当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值前面,排序闭包函数需要返回
true
,反之返回false
。
该例子对一个String
类型的数组进行排序,因此排序闭包函数类型需为(String, String) -> Bool
。
提供排序闭包函数的一种方式是撰写一个符合其类型要求的普通函数,并将其作为ssort(_:)
方法的参数传入:
func backwards(s1: String, s2: String) -> Bool {
return s1 > s2
}
var reversed = names.sort(backwards)
// reversed 为 ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
如果第一个字符串 (s1
) 大于第二个字符串 (s2
),backwards
函数返回true
,表示在新的数组中s1
应该出现在s2
前。 对于字符串中的字符来说,“大于” 表示 “按照字母顺序较晚出现”。 这意味着字母"B"
大于字母"A"
,字符串"Tom"
大于字符串"Tim"
。 其将进行字母逆序排序,"Barry"
将会排在"Alex"
之前。
然而,这是一个相当冗长的方式,本质上只是写了一个单表达式函数 (a > b)。 在下面的例子中,利用闭合表达式语法可以更好的构造一个内联排序闭包。
闭包表达式语法(Closure Expression Syntax)
闭包表达式语法有如下一般形式:
{ (parameters) -> returnType in
statements
}
闭包表达式语法可以使用常量、变量和inout
类型作为参数,不提供默认值。 也可以在参数列表的最后使用可变参数。 元组也可以作为参数和返回值。
下面的例子展示了之前backwards
函数对应的闭包表达式版本的代码:
reversed = names.sort({ (s1: String, s2: String) -> Bool in
return s1 > s2
})
需要注意的是内联闭包参数和返回值类型声明与backwards
函数类型声明相同。 在这两种方式中,都写成了(s1: String, s2: String) -> Bool
。 然而在内联闭包表达式中,函数和返回值类型都写在大括号内,而不是大括号外。
闭包的函数体部分由关键字in
引入。 该关键字表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始。
因为这个闭包的函数体部分如此短以至于可以将其改写成一行代码:
reversed = names.sort( { (s1: String, s2: String) -> Bool in return s1 > s2 } )
这说明sort(_:)
方法的整体调用保持不变,一对圆括号仍然包裹住了函数中整个参数集合。而其中一个参数现在变成了内联闭包(相比于backwards
版本的代码)
根据上下文推断类型(Inferring Type From Context)
因为排序闭包函数是作为sort(_:)
方法的参数进行传入的,Swift可以推断其参数和返回值的类型。 sorted
期望第二个参数是类型为(String, String) -> Bool
的函数,因此实际上String
,String
和Bool
类型并不需要作为闭包表达式定义中的一部分。 因为所有的类型都可以被正确推断,返回箭头 (->
) 和围绕在参数周围的括号也可以被省略:
reversed = names.sort( { s1, s2 in return s1 > s2 } )
实际上任何情况下,通过内联闭包表达式构造的闭包作为参数传递给函数时,都可以推断出闭包的参数和返回值类型,这意味着您几乎不需要利用完整格式构造任何内联闭包。
然而您仍然可以明确写出有着完整格式的闭包。如果完整格式的闭包能够提高代码的可读性,则可以采用完整格式的闭包。而在sort(_:)
方法这个例子里,闭包的目的就是排序,读者能够推测除这个闭包是用于字符串处理的,因为这个闭包是为了处理字符串数组的排序。
单表达式闭包隐式返回(Implicit Return From Single-Expression Clossures)
单行表达式闭包可以通过隐藏return
关键字来隐式返回单行表达式的结果,如上版本的例子可以改写为:
reversed = names.sort( { s1, s2 in s1 > s2 } )
在这个例子中,sort(_:)
方法的第二个参数函数类型明确了闭包必须返回一个Bool
类型值。 因为闭包函数体只包含了一个单一表达式 (s1 > s2
),该表达式返回Bool
类型值,因此这里没有歧义,return
关键字可以省略。
参数名称缩写(Shorthand Argument Names)
Swift 自动为内联函数提供了参数名称缩写功能,您可以直接通过$0
,$1
,$2
来顺序调用闭包的参数。
如果您在闭包表达式中使用参数名称缩写,您可以在闭包参数列表中省略对其的定义,并且对应参数名称缩写的类型会通过函数类型进行推断。 in
关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成:
reversed = names.sort( { $0 > $1 } )
在这个例子中,$0
和$1
表示闭包中第一个和第二个String
类型的参数。
原文出处:http://wiki.jikexueyuan.com/project/swift/chapter2/07_Closures.html