一、閉包表達式(Closure Expression)
在Swift中,可以通過
func和 閉包表達式 定義一個函數(shù)
相當于Objective-C語言中Block
- func函數(shù)
func sum(_ v1: Int, _ v2: Int) -> Int { v1 + v2 }
- 閉包表達式
{
(參數(shù)列表) -> 返回值類型 in
函數(shù)體代碼
}
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))
}
調(diào)用簡寫
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.如果將一個很長的閉包表達式作為函數(shù)的最后一個參數(shù),使用尾隨閉包可以增強函數(shù)的可讀性;尾隨閉包是一個被書寫在函數(shù)調(diào)用括號外面(后面)的閉包表達式;
exec(v1: 10, v2: 20) { v1, v2 in
v1 + v2
}
exec(v1: 10, v2: 20) {
$0 + $1
}
2.如果閉包表達式是函數(shù)的唯一實參,而且使用了尾隨閉包的語法,那就不需要在函數(shù)后面寫圓括號
func exec(fn:(Int, Int) -> Int) {
print(fn(10, 20))
}
調(diào)用尾隨閉包
exec(fn: {
$0 + $1
})
exec() { v1, v2 in
v1 + v2
}
exec{ v1, v2 in
v1 + v2
}
exec { $0 + $1 }
- 示例·數(shù)組排序
從小到大排序
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]
使用函數(shù)
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.一個函數(shù)和他所捕獲的變量/常量環(huán)境組合起來,稱為“閉包”
2.一般指定義在函數(shù)內(nèi)部的函數(shù)
3.一般它捕獲的是外層函數(shù)的局部變量/常量
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.內(nèi)存在堆空間
2.捕獲的局部變量/常量就是對象的成員(存儲屬性)
3.組成閉包的函數(shù)就是類內(nèi)部定義的方法
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())
}
-
注意
如果返回值是函數(shù)類型,那么參數(shù)的修飾要保持統(tǒng)一
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格式的參數(shù)@autoclosure并非只支持最后1個參數(shù)- 空合并運算符
??使用了@autoclosure技術- 有
@autoclosure、無@autoclosure構(gòu)成了函數(shù)重載
1.如果第一個數(shù)大于0,返回第一個數(shù),否則返回第二個數(shù)。
func getFirstPositive(_ v1: Int, _ v2:Int) -> Int {
return v1 > 0 ? v1 : v2
}
getFirstPositive(10, 20)
getFirstPositive(-2, 20)
2.改成函數(shù)類型的參數(shù),可以讓v2延遲加載
func getFirstPositive(_ v1: Int, _ v2: () -> Int) -> Int? {
return v1 > 0 ? v1 : v2()
}
getFirstPositive(-4) { 20 }
3.@autoclosure
//為了避免與期望沖突,使用了`@autoclosure`的地方最好明確注釋清楚這個值會被推遲執(zhí)行
func getFirstPositive(_ v1: Int, _ v2:@autoclosure () -> Int) -> Int? {
return v1 > 0 ? v1 : v2()
}
getFirstPositive(-4, 20) //將20封裝成閉包{ 20 }