閉包概述:(以下是我拷貝的)
閉包(Closures)
- 閉包是自包含的功能代碼塊拳芙,可以在代碼中使用或者用來作為參數(shù)傳值籽孙。
- 在Swift中的閉包與C亲善、OC中的blocks和其它編程語言(如Python)中的lambdas類似凉袱。
- 閉包可以捕獲和存儲(chǔ)上下文中定義的的任何常量和變量的引用傲宜。這就是所謂的變量和變量的自封閉运杭,
- 因此命名為”閉包“("Closures)").Swift還會(huì)處理所有捕獲的引用的內(nèi)存管理。
- 全局函數(shù)和嵌套函數(shù)其實(shí)就是特殊的閉包函卒。
- 閉包的形式有:
- (1)全局函數(shù)都是閉包辆憔,有名字但不能捕獲任何值。
- (2)嵌套函數(shù)都是閉包报嵌,且有名字虱咧,也能捕獲封閉函數(shù)內(nèi)的值。
- (3)閉包表達(dá)式都是無名閉包锚国,使用輕量級語法腕巡,可以根據(jù)上下文環(huán)境捕獲值。
- Swift中的閉包有很多優(yōu)化的地方:
- (1)根據(jù)上下文推斷參數(shù)和返回值類型
- (2)從單行表達(dá)式閉包中隱式返回(也就是閉包體只有一行代碼血筑,可以省略return)
- (3)可以使用簡化參數(shù)名绘沉,如$0, $1(從0開始,表示第i個(gè)參數(shù)...)
- (4)提供了尾隨閉包語法(Trailing closure syntax)
問題:對names中的元素按字母升序排序 (Z最小,A最大)
var names = ["Swift", "Arial", "Soga", "Donary"]
函數(shù)寫法
func backwards(s1: String, s2: String) -> Bool {
return s1 > s2 // 升序排序
}
var reversed = names.sort(backwards)
把上面的普通函數(shù)寫法轉(zhuǎn)換為閉包函數(shù)
reversed = names.sort({
(s1: String, s2: String) -> Bool in
return s1 > s2
})
sort是一個(gè)排序函數(shù)豺总,它通過基于輸出類型排序的閉包函數(shù)车伞,給已知類型的數(shù)組數(shù)據(jù)的值排序。需要一個(gè)閉包參數(shù)作為參數(shù):Sort函數(shù)的完整抽象形態(tài)如下:
names.sort { (String1, String2) -> Bool in
do someting
return Bool
}
sort也是一個(gè)尾隨閉包函數(shù)(Trailing Closures)
如果函數(shù)需要一個(gè)閉包參數(shù)作為參數(shù)喻喳,且這個(gè)參數(shù)是最后一個(gè)參數(shù)另玖,而這個(gè)閉包表達(dá)式又很長時(shí),可以使用尾隨閉包。尾隨閉包可以放在函數(shù)參數(shù)列表外日矫,也就是括號(hào)外赂弓。
如果尾隨閉包函數(shù)只有一個(gè)參數(shù),那么可以把括號(hào)()省略掉哪轿,后面直接跟著閉包盈魁。
尾隨閉包去掉括號(hào)
reversed = names.sort{
(s1: String, s2: String) -> Bool in
return s1 > s2
}
由于參數(shù)傳入時(shí)swift會(huì)進(jìn)行隱式類型推導(dǎo),省去參數(shù)類型
reversed = names.sort{
(s1,s2) -> Bool in
return s1 > s2
}
同理由于結(jié)果return時(shí)swift會(huì)進(jìn)行隱式類型推導(dǎo)窃诉,省去返回值類型
reversed = names.sort{
(s1,s2) in
return s1 > s2
}
既然類型都沒了杨耙,閉包里面自帶了一套默認(rèn)的參數(shù)名,你可以不聲明閉包參數(shù)列表飘痛。
第一參數(shù):$0,第二參數(shù):$1 ...
這是后閉包函數(shù)聲明中的參數(shù)列表和返回值類型都沒了
那么關(guān)鍵字in也省了吧珊膜,直接寫內(nèi)部結(jié)構(gòu)體
reversed = names.sort{
return $0 > $1
}
如果內(nèi)部結(jié)構(gòu)體中只有return這么一句話,return也能省
reversed = names.sort{$0 > $1}
最簡單的寫法宣脉,只留下操作符车柠,注意,這時(shí)候尾閉包使用的是()
這種方法只適用于閉包中只有"默認(rèn)參數(shù)名"和"運(yùn)算符"這兩者的情況
reversed = names.sort(>)
閉包的運(yùn)用:捕獲值(內(nèi)嵌函數(shù)捕獲外部函數(shù)中定義的常量和變量)
func increment(amount amount: Int) -> (() -> Int) {
var total = 0
func incrementAmount() -> Int {
total += amount // total是外部函數(shù)體內(nèi)的變量塑猖,這里是可以捕獲到的
return total
}
return incrementAmount // 返回的是一個(gè)嵌套函數(shù)(閉包)
}
// 閉包是引用類型竹祷,所以incrementByTen聲明為常量也可以修改total
let incrementByTen = increment(amount: 10)
incrementByTen() // return 10,incrementByTen是一個(gè)閉包
incrementByTen() // return 20
incrementByTen() // return 30
let incrementByOne = increment(amount: 1)
incrementByOne() // return 1
incrementByOne() // return 2
incrementByOne() // return 3
//函數(shù)本身不占內(nèi)存,使用賦值后才占.
//所以多次調(diào)用同一個(gè)函數(shù)不會(huì)對其他調(diào)用該函數(shù)的變量造成影響
//incrementByTen和incrementByOne不會(huì)應(yīng)為他們都使用increment而相互影響
incrementByTen() // return 40
incrementByOne() // return 4