如果您需要將一個(gè)很長(zhǎng)的閉包表達(dá)式作為最后一個(gè)參數(shù)傳遞給函數(shù),可以使用尾隨閉包來(lái)增強(qiáng)函數(shù)的可讀性。 尾隨閉包是一個(gè)書(shū)寫(xiě)在函數(shù)括號(hào)之后的閉包表達(dá)式,函數(shù)支持將其作為最后一個(gè)參數(shù)調(diào)用。
func someFunctionThatTakesAClosure(closure: () -> ()) {
// 函數(shù)體部分
}
// 以下是不使用尾隨閉包進(jìn)行函數(shù)調(diào)用
someFunctionThatTakesAClosure({
// 閉包主體部分
})
// 以下是使用尾隨閉包進(jìn)行函數(shù)調(diào)用
someFunctionThatTakesAClosure() {
// 閉包主體部分
}
注意:
如果函數(shù)只需要閉包表達(dá)式一個(gè)參數(shù),當(dāng)您使用尾隨閉包時(shí),您甚至可以把()省略掉。
在上例中作為sort函數(shù)參數(shù)的字符串排序閉包可以改寫(xiě)為:
reversed = sort(names) { $0 > $1 }
當(dāng)閉包非常長(zhǎng)以至于不能在一行中進(jìn)行書(shū)寫(xiě)時(shí),尾隨閉包變得非常有用。 舉例來(lái)說(shuō),Swift 的Array類(lèi)型有一個(gè)map方法,其獲取一個(gè)閉包表達(dá)式作為其唯一參數(shù)。 數(shù)組中的每一個(gè)元素調(diào)用一次該閉包函數(shù),并返回該元素所映射的值(也可以是不同類(lèi)型的值)。 具體的映射方式和返回值類(lèi)型由閉包來(lái)指定。
當(dāng)提供給數(shù)組閉包函數(shù)后,map方法將返回一個(gè)新的數(shù)組,數(shù)組中包含了與原數(shù)組一一對(duì)應(yīng)的映射后的值。
下例介紹了如何在map方法中使用尾隨閉包將Int類(lèi)型數(shù)組[16,58,510]轉(zhuǎn)換為包含對(duì)應(yīng)String類(lèi)型的數(shù)組["OneSix", "FiveEight", "FiveOneZero"]:
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
如上代碼創(chuàng)建了一個(gè)數(shù)字位和它們名字映射的英文版本字典。 同時(shí)定義了一個(gè)準(zhǔn)備轉(zhuǎn)換為字符串的整型數(shù)組。
您現(xiàn)在可以通過(guò)傳遞一個(gè)尾隨閉包給numbers的map方法來(lái)創(chuàng)建對(duì)應(yīng)的字符串版本數(shù)組。 需要注意的時(shí)調(diào)用numbers.map不需要在map后面包含任何括號(hào),因?yàn)槠渲恍枰獋鬟f閉包表達(dá)式這一個(gè)參數(shù),并且該閉包表達(dá)式參數(shù)通過(guò)尾隨方式進(jìn)行撰寫(xiě):
let strings = numbers.map {
(var number) -> String in
var output = ""
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
}
// strings 常量被推斷為字符串類(lèi)型數(shù)組,即 String[]
// 其值為 ["OneSix", "FiveEight", "FiveOneZero"]
map在數(shù)組中為每一個(gè)元素調(diào)用了閉包表達(dá)式。 您不需要指定閉包的輸入?yún)?shù)number的類(lèi)型,因?yàn)榭梢酝ㄟ^(guò)要映射的數(shù)組類(lèi)型進(jìn)行推斷。
閉包number參數(shù)被聲明為一個(gè)變量參數(shù)(變量的具體描述請(qǐng)參看常量參數(shù)和變量參數(shù)),因此可以在閉包函數(shù)體內(nèi)對(duì)其進(jìn)行修改。閉包表達(dá)式制定了返回類(lèi)型為String,以表明存儲(chǔ)映射值的新數(shù)組類(lèi)型為String。
閉包表達(dá)式在每次被調(diào)用的時(shí)候創(chuàng)建了一個(gè)字符串并返回。 其使用求余運(yùn)算符 (number % 10) 計(jì)算最后一位數(shù)字并利用digitNames字典獲取所映射的字符串。
注意:
字典digitNames下標(biāo)后跟著一個(gè)嘆號(hào) (!),因?yàn)樽值湎聵?biāo)返回一個(gè)可選值 (optional value),表明即使該 key 不存在也不會(huì)查找失敗。
在上例中,它保證了number % 10可以總是作為一個(gè)digitNames字典的有效下標(biāo) key。
因此嘆號(hào)可以用于強(qiáng)制解析 (force-unwrap) 存儲(chǔ)在可選下標(biāo)項(xiàng)中的String類(lèi)型值。
從digitNames字典中獲取的字符串被添加到輸出的前部,逆序建立了一個(gè)字符串版本的數(shù)字。 (在表達(dá)式number % 10中,如果number為16,則返回6,58返回8,510返回0)。
number變量之后除以10。 因?yàn)槠涫钦麛?shù),在計(jì)算過(guò)程中未除盡部分被忽略。 因此 16變成了1,58變成了5,510變成了51。
整個(gè)過(guò)程重復(fù)進(jìn)行,直到number /= 10為0,這時(shí)閉包會(huì)將字符串輸出,而map函數(shù)則會(huì)將字符串添加到所映射的數(shù)組中。
上例中尾隨閉包語(yǔ)法在函數(shù)后整潔封裝了具體的閉包功能,而不再需要將整個(gè)閉包包裹在map函數(shù)的括號(hào)內(nèi)。