闭包
闭包,closure,类似于oc中block及其他语言中lambda
闭包三种形式:
- 全局函数:有名字,不捕获值
- 嵌套函数:有名字,从外围函数捕获值
- 闭包表达式:无名字,从上下文捕获值
闭包表达式
嵌套函数
func compare(a: Int, _ b: Int, _ cmp: (Int, Int) -> Bool) -> Int
{
return cmp(a, b) ? a : b
}
func use_compare()
{
func cmp(a: Int, b: Int) -> Bool
{
return a > b
}
let result = compare(8, 5, cmp)
print("result = \(result)")
}
完整闭包表达式
func compare(a: Int, _ b: Int, _ cmp: (Int, Int) -> Bool) -> Int
{
return cmp(a, b) ? a : b
}
func use_compare()
{
let result = compare(8, 5, { (a: Int, b: Int) -> Bool in return a > b })
print("result = \(result)")
}
总结:
- 完整闭包表达式包括参数类型,参数名,返回类型,函数体(以in起始),闭包表达式包括在{}中,与嵌套函数相比,omit了函数名和argument label
- let cmp: (Int, Int) -> Bool = { (a: Int, b: Int) -> Bool in return a > b }是合法的,只要参数类型和返回类型一致,显然闭包表达式类型为函数类型
类型推断
func compare(a: Int, _ b: Int, _ cmp: (Int, Int) -> Bool) -> Int
{
return cmp(a, b) ? a : b
}
func use_compare()
{
let result = compare(8, 5, { a, b in return a > b })
print("result = \(result)")
}
总结:
- 闭包表达式赋值给函数类型时,可omit参数类型以及返回类型,进一步可omit包围参数名的圆括号,因为可从函数类型推断出闭包表达式参数类型和返回类型
- let cmp: (Int, Int) -> Bool = { a, b in return a > b }是合法的,可从左值函数类型推断出右值闭包表达式参数类型和返回类型
隐式return
func compare(a: Int, _ b: Int, _ cmp: (Int, Int) -> Bool) -> Int
{
return cmp(a, b) ? a : b
}
func use_compare()
{
let result = compare(8, 5, { a, b in a > b })
print("result = \(result)")
}
总结:
- 只有唯一一条表达式的闭包表达式可omit return,闭包表达式把唯一一条表达式值作为闭包表达式返回值隐式返回
- let cmp: (Int, Int) -> Bool = { a, b in a > b }是合法的,唯一一条表达式值作为闭包表达式返回值隐式返回
形参速记
func compare(a: Int, _ b: Int, _ cmp: (Int, Int) -> Bool) -> Int
{
return cmp(a, b) ? a : b
}
func use_compare()
{
let result = compare(8, 5, { $0 > $1 })
print("result = \(result)")
}
总结:
- 可进一步omit形参名(包括in),使用形参速记$0,$1等,从0起始
- let cmp: (Int, Int) -> Bool = { $0 > $1 }
操作符重载
func compare(a: Int, _ b: Int, _ cmp: (Int, Int) -> Bool) -> Int
{
return cmp(a, b) ? a : b
}
func use_compare()
{
let result = compare(8, 5, >)
print("result = \(result)")
}
总结:
- 如果参数类型支持相应的操作符重载,可omit参数,只保留重载的操作符
- let cmp: (Int, Int) -> Bool = >非法
拖尾闭包
func compare(a: Int, _ b: Int, cmp: (Int, Int) -> Bool) -> Int
{
return cmp(a, b) ? a : b
}
func use_compare()
{
let result = compare(8, 5) { (a: Int, b: Int) -> Bool in return a > b }
print("result = \(result)")
}
总结:
- 如果最后一个参数是函数类型(包括只有一个参数),实参使用闭包表达式传时,可直接把闭包表达式写在函数调用后面,并且可omit该参数argument label,当闭包表达式比较长时使用拖尾闭包增强代码可读性
捕获值
嵌套函数捕获
func makeIncrementer(forIncrement amount: Int) -> () -> Int
{
var runningTotal = 0
func incrementer() -> Int
{
runningTotal += amount
return runningTotal
}
return incrementer
}
func nestedFuncCapture()
{
let incrementBy5 = makeIncrementer(forIncrement: 5)
let incrementBy8 = makeIncrementer(forIncrement: 8);
print(incrementBy5())
print(incrementBy5())
print(incrementBy5())
print(incrementBy8())
print(incrementBy8())
print(incrementBy8())
}
output:
5
10
15
8
16
24
总结:
- 可把嵌套函数理解为外围函数定义的局部对象,因此两次返回的嵌套函数指向的不是同一个函数对象,它们相互独立,互不影响
- 嵌套函数捕获外围函数对象(参数对象和局部对象)理解为嵌套函数保存了指向这些对象的引用,嵌套函数被调用时才获取这些对象值