Closure是自包含的代码块,可以在代码中传递和使用,类似于OC中的Block。
Closure可以捕获或者存储定义它的上下文中的变量的引用。
全局方法或者嵌套方法是特殊情况下的Closure,Closure有3中类型:
- 全局方法是有名称但是不捕获任何变量的Closure。
- 嵌套方法是有名称且可以捕获变量的Closure,可以从它的封闭函数中捕获值。
- 闭包表达式是用简洁语法写的未命名的闭包,可捕获上下文中的值。
1. 闭包表达式
嵌套函数是一种命名和定义作为较大方法一部分的自包含代码块的便洁的方法。但是,有时候编写较短的类似函数的构造是非常有用的,尤其是将函数作为另一个函数的参数的时候。
Closure就是一种这样的方式,它可以通过更简洁的语法声明内联闭包,但是不会造成任何值的丢失。闭包表达式为此设置了几个优化语法,我们就以sort(by:)
这个函数为例来逐步简化代码:
Swift标准库提供了一个sort(by:)
函数,该函数通过开发者返回的代码块,来为已知类型的数组排序。
func sorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element]
我们看到,该函数的参数类型为(Element, Element) throws -> Bool
,我们声明一个这样的方法
private func orderFunc(a : Int, b : Int) -> Bool {
return a > b
}
再使用该方法为给定的数组排序
var ints = [10, 2, 1000, 8]
let a = ints.sorted(by: orderFunc(a:b:))
//[1000, 10, 8, 2]
其实我们要做的只是写一句a>b
,其它的代码都是为这一句代码服务的,这么看来,上面的步骤颇为繁琐,我们可以通过Closure来解决这一问题。
(1)、 Closure表达式的语法
{ (parameters) -> return type in
statements
}
Closure的参数可以是in-out
参数,但是不能有默认值;如果你指定可变参数,也可以使用可变参数;元组也可以作为参数或者返回值。
我们现在来用Closure重新写一下sort方法
let result = ints.sorted { (a : Int, b : Int) -> Bool in
return a > b
}
看起来比上面简洁了一点,由于我们的Closure的代码比较少,所以我们可以放在一行:
let result = ints.sorted { (a : Int, b : Int) -> Bool in return a > b }
现在更加简洁了
(2)、从上下文推断类型
由于这个排序闭包是作为sorted
方法的参数,所以Swift可以推断它的参数和返回值。这个sort(by:)
方法是被一个String数组调用的,所以该方法的参数是(String, String) -> Bool
型的,这就意味着我们可以省去参数类型(String, String)
和返回值类型Bool
:
let result = ints.sorted { a, b in return a > b }
当然,为了防止歧义,开发者可以不省略参数类型和返回值类型。
(3)、从单表达式闭包中隐式返回
单表达式闭包``可以省略
return`关键词,隐式地返回结果,注意,只能是单表达式闭包
let result = ints.sorted { a, b in a > b }
(4)、简写参数名
Swift为内联闭包自动提供了速记参数名,它们可以被用作引用闭包的参数值,比如1,$2等。
let result = ints.sorted { $0 > $1 }
(5)、操作符方法
如果单表达式闭包的返回值是Bool类型,可以直接使用大于号或者小于号。
let result = ints.sorted(by: >)