在 Swift 中的閉包類似于結(jié)構(gòu)塊,并可以在任何地方調(diào)用,它就像 C 和 Objective C 語言內(nèi)置的函數(shù)。 函數(shù)內(nèi)部定義的常數(shù)和變量引用可被捕獲并存儲在閉包。函數(shù)被視為封閉的特殊情況,它有 3 種形式。
| 全局函數(shù) | 嵌套函數(shù) | 閉合表達(dá)式 |
| 有名字但不捕獲任何值 | 有名字,從封閉函數(shù)捕捉值 | 無名閉包從相鄰塊捕獲值 |
在 Swift 語言閉合表達(dá)式,如下優(yōu)化,重量輕語法風(fēng)格,其中包括。
推導(dǎo)參數(shù)并從上下文菜單返回值的類型
從單封表達(dá)的隱性返回
簡略參數(shù)名稱
尾部閉包語法
下面是一個(gè)通用的語法定義用于閉包,它接受參數(shù)并返回?cái)?shù)據(jù)的類型:
{(parameters) -> return type in
statements
}
下面是一個(gè)簡單的例子:
let studname = { println("Welcome to Swift Closures") } studname()
當(dāng)我們使用 playground 運(yùn)行上面的程序,我們得到以下結(jié)果
Welcome to Swift Closures
以下閉包接受兩個(gè)參數(shù)并返回一個(gè)布爾值:
{(Int, Int) -> Bool in
Statement1
Statement 2
---
Statement n
}
下面是一個(gè)簡單的例子:
let divide = {(val1: Int, val2: Int) -> Int in return val1 / val2 } let result = divide(200, 20) println (result)
當(dāng)我們使用 playground 運(yùn)行上面的程序,我們得到以下結(jié)果
10
以便捷的方式命名來定義代碼塊可以通過嵌套函數(shù)實(shí)現(xiàn)的。取而代之代表整個(gè)函數(shù)聲明及名稱構(gòu)造用來表示函數(shù)。代表函數(shù)的語法清晰,簡短聲明是通過封閉的表達(dá)來實(shí)現(xiàn)的。
排序字符串是 Swift 中保留的函數(shù) “sorted”,這是在標(biāo)準(zhǔn)庫中已提供實(shí)現(xiàn)。該函數(shù)將所述給定的字符串進(jìn)行遞增順序排序并返回具有相同的尺寸,并在舊數(shù)組中相同數(shù)據(jù)類型的一個(gè)新的數(shù)組的元素。舊的數(shù)組保持不變。
兩個(gè)參數(shù)的排序在函數(shù)內(nèi)部表示:
已知類型的值表示為數(shù)組
數(shù)組的內(nèi)容 (Int,Int) ,并返回一個(gè)布爾值(Bool),如果數(shù)組排序不好就會返回true,否則將返回false。
普通函數(shù)帶輸入字符串被寫入,并傳遞給排序函數(shù)獲得字符到新的數(shù)組,如下面所示:
func ascend(s1: String, s2: String) -> Bool { return s1 > s2 } let stringcmp = ascend("swift", "great") println (stringcmp)
當(dāng)我們使用 playground 運(yùn)行上面的程序,我們得到以下結(jié)果
true
最初的數(shù)組排序給定為 "Swift" 和 "great"。函數(shù)用來數(shù)組排序被聲明為字符串?dāng)?shù)據(jù)類型,并且返回類型為布爾型。 兩個(gè)字符串進(jìn)行比較,并以升序排序,并存儲在新的數(shù)組。如果排序執(zhí)行成功,該函數(shù)將返回true;否則將返回 false。
閉包表達(dá)式語法用法
常量參數(shù)
可變參數(shù) 和 inout 參數(shù)
閉包表達(dá)不支持的默認(rèn)值??勺儏?shù)和參數(shù)元組也可以用來作為參數(shù)類型和返回類型。
let sum = {(no1: Int, no2: Int) -> Int in return no1 + no2 } let digits = sum(10, 20) println(digits)
當(dāng)我們使用 playground 運(yùn)行上面的程序,我們得到以下結(jié)果
30
在函數(shù)聲明中提到的參數(shù)和返回類型聲明,也可通過使用 'in' 關(guān)鍵字內(nèi)聯(lián)閉包表達(dá)式函數(shù)表示。 一旦聲明參數(shù)及其返回類型“in”關(guān)鍵字,則用于表示閉包體。
在這里,排序函數(shù)的第二個(gè)參數(shù)的函數(shù)類型明確指出,一個(gè)布爾值必須由閉包返回。因?yàn)殚]包體內(nèi)含有一個(gè)表達(dá)式(s1 > s2)返回一個(gè)布爾值, 不會出現(xiàn)歧義,其返回關(guān)鍵字可以省略。
要返回一個(gè)表達(dá)式語句在閉包中, “return” 關(guān)鍵字在其聲明部分被省略。
let count = [5, 10, -6, 75, 20] var descending = sorted(count, { n1, n2 in n1 > n2 }) var ascending = sorted(count, { n1, n2 in n1 < n2 }) println(descending) println(ascending)
當(dāng)我們使用 playground 運(yùn)行上面的程序,我們得到以下結(jié)果
[75, 20, 10, 5, -6] [-6, 5, 10, 20, 75]
該語句本身明確規(guī)定,當(dāng) string1 大于 string2 返回 true,否則為false,因此return語句省略。
考慮兩個(gè)數(shù)相加。我們知道相加后將返回整數(shù)數(shù)據(jù)類型。因此,已知類型的閉包聲明
let sub = {(no1: Int, no2: Int) -> Int in return no1 - no2 } let digits = sub(10, 20) println(digits)
當(dāng)我們使用 playground 運(yùn)行上面的程序,我們得到以下結(jié)果
-10
Swift 自動(dòng)提供簡寫參數(shù)名內(nèi)聯(lián)閉包, 可以使用由 $0,$1,$2 等等名稱,指的是封閉的參數(shù)值。
var shorthand: (String, String) -> String shorthand = { $1 } println(shorthand("100", "200"))
在這里,$0 和 $1 參考閉包的第一和第二個(gè)字符串參數(shù)。
當(dāng)我們使用 playground 運(yùn)行上面的程序,我們得到以下結(jié)果
200
Swift 方便用戶來表示內(nèi)嵌閉包為縮寫參數(shù)名為:$0, $1, $2 --- $n.
閉包參數(shù)列表中被省略定義部分,當(dāng)我們表示內(nèi)部閉包表達(dá)式簡寫參數(shù)名。 根據(jù)函數(shù)類型簡寫參數(shù)名稱將被導(dǎo)出。由于簡寫參數(shù)表達(dá)體所定義的 'in' 關(guān)鍵字被省略。
Swift 提供了一種簡單的方法訪問的成員,只需提供操作符函數(shù)作為閉包。 在前面的例子關(guān)鍵字“Bool”是用來比較兩個(gè)字符串,相等返回“true”,否則返回“false”。
表達(dá)式即使在閉包中變得簡單在操作函數(shù):
let numb = [98, -20, -30, 42, 18, 35] var sortedNumbers = numb.sorted({ (left: Int, right: Int) -> Bool in return left < right }) let asc = numb.sorted(<) println(asc)
當(dāng)我們使用 playground 運(yùn)行上面的程序,我們得到以下結(jié)果
[-30, -20, 18, 35, 42, 98]
傳遞這個(gè)函數(shù)的最后一個(gè)參數(shù)到閉合表達(dá)式使用“尾隨閉包”聲明。它使用 {} 寫在函數(shù)()外部。當(dāng)它不能寫入函數(shù)內(nèi)聯(lián)在一行上,使用它是需要。
reversed = sorted(names) { $0 > $1}
其中 {$0 > $1} 表示為外部(名稱)聲明尾隨閉包。
import Foundation var letters = ["North", "East", "West", "South"] let twoletters = letters.map({ (state: String) -> String in return state.substringToIndex(advance(state.startIndex, 2)).uppercaseString }) let stletters = letters.map() { $0.substringToIndex(advance($0.startIndex, 2)).uppercaseString } println(stletters)
當(dāng)我們使用 playground 運(yùn)行上面的程序,我們得到以下結(jié)果
[NO, EA, WE, SO]
在閉包的幫助下 Swift 完成捕捉常量和變量的值。它還參考修改值,即使常量和變量在閉包體已經(jīng)不存。
捕獲常數(shù)和變量值是通過使用嵌套函數(shù)寫入函數(shù),這是使用其它函數(shù)體來實(shí)現(xiàn)的。
一個(gè)嵌套函數(shù)捕獲
外部函數(shù)參數(shù)
捕捉常量和外部函數(shù)中定義的變量
Swift 中當(dāng)常量或變量在函數(shù)中聲明,引用到變量也自動(dòng)地被閉合創(chuàng)建。它也提供工具來引用兩個(gè)以上的變量作為同一閉合如下:
let decrem = calcDecrement(forDecrement: 18) decrem()
在這里,oneDecrement 和 遞減變量都指向同一個(gè)內(nèi)存塊閉合參考。
func calcDecrement(forDecrement total: Int) -> () -> Int { var overallDecrement = 100 func decrementer() -> Int { overallDecrement -= total println(overallDecrement) return overallDecrement } return decrementer } let decrem = calcDecrement(forDecrement: 18) decrem() decrem() decrem()
當(dāng)我們使用 playground 運(yùn)行上面的程序,我們得到以下結(jié)果:
82 64 46
當(dāng)每一個(gè)外部函數(shù) calcDecrement 調(diào)用時(shí)都會調(diào)用 decrementer()函數(shù) 并通過值 18 遞減,并在外部函數(shù) calcDecrement 的幫助下返回結(jié)果。在這里,calcDecrement 作為一個(gè)閉合。
即使函數(shù) decrement()沒有任何參數(shù),閉合默認(rèn)情況下是指變量的"整體遞減“ “total” 通過獲取其值。為指定的變量的值副本被使用新的 decrementer()函數(shù)存儲。Swift 通過處理存儲器管理功能分配和釋放存儲器空間當(dāng)變量在不使用。