引言
一开始听说闭包Closures这个词是来自于Objective-C中的Block,乍一眼看起来特别像函数function,用着用着又有点像代理delegate。
官方对闭包的解释是自包含的函数代码块,可以在代码中传递和使用。OC中Closures经常用于函数回调,当然Swift中也同样,之所以第一篇Swift学习笔记就想介绍Closures,是因为它是在太神奇了,神奇到可以化繁为简,简化到看不懂代码!!!
Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进行语法优化,主要优化如下:
1.利用上下文推断参数和返回值类型
2.隐式返回单表达式闭包,即单表达式闭包可以省略return关键字
3.参数名称缩写
4.尾随(Trailing)闭包语法
因为Swift语言每次迭代的改动内容都较大,目前使用的代码版本是Swift2。
正文
本文将介绍一个简单的例子,对字符串数组的排序,这也是官方文档中的Demo。通过这个例子,大家会看到Swift是如何优雅地精简闭包表达式。
第一步:准备工作
(1)初始化一个字符串数组:
let names = ["Chris","Alex","Ewa","Barry","Daniella"]
(2)初始化一个对字符串排序函数
func backwards(s1:String, s2:String) ->Bool {
returns1 > s2
}
backwards函数很简单。如果字符串s1大于字符串s2,backwards函数会返回true,表示在新的数组中s1出现在s2前。 对于字符串中的字符来说,“大于” 表示 “按照字母顺序较晚出现”。 这意味着字母"B"大于字母"A",字符串"Tom"大于字符串"Tim"。 其将进行字母逆序排序,"Barry"将会排在"Alex"之前。
第二步:对字符串数组进行排序
var reversed = names.sort(backwards)
sort函数会根据传入闭包函数的规则对names字符串数组进行排序,排序后names数组中的值为["Ewa", "Daniella", "Chris", "Barry", "Alex"],实现了对字符串数组的倒序排序。假如将backwards函数中的">"改为"<",那么排序的结果则是["Alex", "Barry", "Chris", "Daniella", "Ewa"],实现对字符串数组的顺序排序。
优化
上面这个简单的例子通过闭包函数实现了对字符串数组的排序,sort函数可以接受闭包函数作为参数进行计算。但是Swift可以更简单的方法来实现闭包函数,用闭包表达式。
闭包表达式语法有如下一般形式:
{ (parameters) -> Type in return statements}
parameters表示参数值,可以有一个或多个;Type表示返回类型; statements表示实现的规则;in和return是关键字。
在进行简化前,首先来复习下上面的字符串数组排序代码:
func backwards(s1:String, s2:String) ->Bool {
return s1 > s2
}
var reversed = names.sort(backwards)
如果用发功的功力来表示简化的程度,那么
三成功力-内联闭包表达式:
var reversed = names.sort({ (s1:String, s2:String) ->Bool in return s1 > s2})
{ (s1:String, s2:String) ->Bool in return s1 > s2}这个内联闭包表达式代替了原先backwards函数,关键字in表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始。
五成功力-根据上下文推断类型:
var reversed = names.sort({ s1, s2 in return s1 > s2})
排序闭包表达式作为sort函数的参数进行传入,Swift可以推断其参数和返回值的类型。sort函数期望参数的类型为(String, String) -> Bool,因此实际上String,String和Bool类型并不需要作为闭包表达式定义中的一部分。 因为所有的类型都可以被正确推断,返回箭头 (->) 和围绕在参数周围的括号也可以被省略。实际上任何情况下,通过内联闭包表达式构造的闭包作为参数传递给函数时,都可以推断出闭包的参数和返回值类型,这意味着几乎不需要利用完整格式构造任何内联闭包。
六成功力-单表达式闭包隐式返回:
var reversed = names.sort({ s1, s2 in s1 > s2})
单行闭包表达式可以通过隐藏return关键字来隐式返回单行表达式的结果。
八成功力-参数名称缩写:
var reversed = names.sort({ $0 > $1 })
Swift 自动为内联函数提供了参数名称缩写功能,可以直接通过$0,$1,$2来顺序调用闭包的参数,$0表示第一个参数,$1表示第二个参数,以此类推。如果在闭包表达式中使用参数名称缩写,可以在闭包参数列表中省略对其的定义,并且对应参数名称缩写的类型会通过函数类型进行推断。in关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成。
十成功力-运算符函数:
var reversed = names.sort(>)
Swift 的String类型定义了关于大于号 (>) 的字符串实现,其作为一个函数接受两个String类型的参数并返回Bool类型的值。 而这正好与sort函数的参数需要的函数类型相符合。 因此,可以简单地传递一个大于号(>),Swift可以自动推断出使用大于号的字符串函数实现。
到目前为止,Swift已经完美的呈现了何为优雅。为了增强代码的可读性,Swift还添加了一项锦上添花的功能,尾随闭包,代码如下:
var reversed = names.sort(){ $0 > $1 }
闭包表达式尾随在sort函数的后面,使得代码更加的整洁优雅。
总结
Swift大法好,谁用谁知道!!!