一、闭包表达式(Closure Expression)
在Swift中,可以通过
func
和 闭包表达式 定义一个函数
相当于Objective-C语言中Block
- func函数
func sum(_ v1: Int, _ v2: Int) -> Int { v1 + v2 }
- 闭包表达式
{
(参数列表) -> 返回值类型 in
函数体代码
}
var fn = {
(v1: Int, v2: Int) -> Int in
return v1 + v2
}
fn(10, 20)
{
(v1: Int, v2: Int) -> Int in
return v1 + v2
}(10, 20)
- 闭包表达式的简写
func exec(v1: Int, v2: Int, fn:(Int, Int) -> Int) {
print(fn(v1, v2))
}
调用简写
exec(v1: 10, v2: 20, fn: { (v1: Int, v2: Int) in
return v1 + v2
})
exec(v1: 10, v2: 20, fn: { v1, v2 in
return v1 + v2
})
exec(v1: 10, v2: 20, fn: { v1, v2 in
v1 + v2
})
exec(v1: 10, v2: 20, fn: {
$0 + $1
})
exec(v1: 10, v2: 20, fn: +)
- 尾随闭包
1.如果将一个很长的闭包表达式作为函数的最后一个参数,使用尾随闭包可以增强函数的可读性;尾随闭包是一个被书写在函数调用括号外面(后面)的闭包表达式;
exec(v1: 10, v2: 20) { v1, v2 in
v1 + v2
}
exec(v1: 10, v2: 20) {
$0 + $1
}
2.如果闭包表达式是函数的唯一实参,而且使用了尾随闭包的语法,那就不需要在函数后面写圆括号
func exec(fn:(Int, Int) -> Int) {
print(fn(10, 20))
}
调用尾随闭包
exec(fn: {
$0 + $1
})
exec() { v1, v2 in
v1 + v2
}
exec{ v1, v2 in
v1 + v2
}
exec { $0 + $1 }
- 示例·数组排序
从小到大排序
var nums = [10, 7, 4, 8, 1, 5, 3, 6, 2, 0, 9]
nums.sort()
print(nums) //[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
使用函数
func cmp(i1: Int, i2: Int) -> Bool {
//大的排在前面
// 返回true:i1排在i2前面; false:i1排在i2后面
return i1 > i2
}
nums.sort(by: cmp)
print(nums)//[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
使用闭包表达式
nums.sort(by: { (i1: Int, i2: Int) -> Bool in
return i1 < i2
})
nums.sort(by: { i1, i2 in
return i1 < i2
})
nums.sort(by: { $0 < $1 })
nums.sort(by: < )
//尾随闭包简写
nums.sort(){ $0 < $1 }
nums.sort { $0 < $1 }
- 忽略实参
func exec(fn:(Int, Int) -> Int) {
print(fn(10, 20))
}
exec { _ ,_ in
return 10
}
二、闭包(Closure)
-
定义
1.一个函数和他所捕获的变量/常量
环境组合起来,称为“闭包”
2.一般指定义在函数内部的函数
3.一般它捕获的是外层函数的局部变量/常量
typealias Fn = (Int) -> Int
func getFn() -> Fn {
//局部变量
var num = 0
func plus(_ i: Int) -> Int {
num += i
return num
}
//返回的plus和num形成了闭包
return plus
}
var fn = getFn()
print(fn(1))
// 1、3、6、10
-
可以把闭包想象成某个类的实例对象
1.内存在堆空间
2.捕获的局部变量/常量就是对象的成员(存储属性)
3.组成闭包的函数就是类内部定义的方法
class Closure {
var num = 0
func plus(_ i: Int) -> Int {
num += i
return num
}
}
var cs = Closure()
print("Class ",cs.plus(1))
print("Class ",cs.plus(2))
- 示例1 - 对应关系
typealias Fn = (Int) -> (Int, Int)
func getFns() -> (Fn, Fn) {
var num1 = 0
var num2 = 0
func plus(_ i: Int) -> (Int, Int) {
num1 += i
num2 += i << 1
return (num1, num2)
}
func minus(_ i: Int) -> (Int, Int) {
num1 -= i
num2 -= i << 1
return (num1, num2)
}
return (plus, minus)
}
let (p, m) = getFns()
p(5) //(5, 10)
m(4) //(1, 2)
class Closure {
var num1 = 0
var num2 = 0
func plus(_ i: Int) -> (Int, Int) {
num1 += i
num2 += i << 1
return (num1, num2)
}
func minus(_ i: Int) -> (Int, Int) {
num1 -= i
num2 -= i << 1
return (num1, num2)
}
}
var cs = Closure()
cs.plus(5)
cs.minus(4)
- 示例2 - 对应关系
var functions: [() -> Int] = []
for i in 1...3 {
functions.append {
return i
}
} // [(Function), (Function), (Function)]
for f in functions {
print("-->",f())
}
class Closure {
var i: Int
init(_ i: Int) {
self.i = i
print("-------- \(i)")
}
func getFn() -> Int {
return i
}
}
var clses : [Closure] = []
for i in 1...3 {
let c = Closure(i)
clses.append(c)
}
for cls in clses {
print(cls.getFn())
}
-
注意
如果返回值是函数类型,那么参数的修饰要保持统一
func add(_ num: Int) -> (inout Int) -> Void {
func plus(v: inout Int) {
v += num
}
return plus
}
var num = 5
add(20)(&num)
print("num:",num)
三、自动闭包(Automatic Closure)
@autoclosure
会自动将20封装成闭包{ 20 }
@autoclosure
只支持() -> T
格式的参数@autoclosure
并非只支持最后1个参数- 空合并运算符
??
使用了@autoclosure
技术- 有
@autoclosure
、无@autoclosure
构成了函数重载
1.如果第一个数大于0,返回第一个数,否则返回第二个数。
func getFirstPositive(_ v1: Int, _ v2:Int) -> Int {
return v1 > 0 ? v1 : v2
}
getFirstPositive(10, 20)
getFirstPositive(-2, 20)
2.改成函数类型的参数,可以让v2延迟加载
func getFirstPositive(_ v1: Int, _ v2: () -> Int) -> Int? {
return v1 > 0 ? v1 : v2()
}
getFirstPositive(-4) { 20 }
3.@autoclosure
//为了避免与期望冲突,使用了`@autoclosure`的地方最好明确注释清楚这个值会被推迟执行
func getFirstPositive(_ v1: Int, _ v2:@autoclosure () -> Int) -> Int? {
return v1 > 0 ? v1 : v2()
}
getFirstPositive(-4, 20) //将20封装成闭包{ 20 }