閉包在Swift中很是有用。通俗的解釋就是一個Int類型裏存儲着一個整數,一個String類型包含着一串字符,一樣,閉包是一個包含着函數的類型。有了閉包,你就能夠處理不少在一些古老的語言中不能處理的事情。這是由於閉包使用的多樣性,好比你能夠將閉包賦值給一個變量,你也能夠將閉包做爲一個函數的參數,你甚至能夠將閉包做爲一個函數的返回值。它的強大之處可見一斑。express
在Swift的不少文檔教材中都說函數是「一等公民」,起初我還不是很理解「一等公民」是什麼意思,但當我理解了閉包以及它的強大功能後,我恍然大悟、茅塞頓開、醍醐灌頂。原來閉包的這些特性就是「一等公民」的特性啊!參見維基百科First-class citizen。swift
Swift中的閉包相似Objective-C中的Block。其實,若是你想在Swift中實現Objective-C裏的Block功能,你能夠直接使用閉包來代替。Block和閉包的區別只是語法的不一樣而已,並且閉包的可讀性比較強。數組
函數是閉包嗎?閉包
雖然你尚未意識到,但咱們確實已經在Swift中這麼用了。Swift中的函數就是閉包,在Apple的官方文檔中有這樣的描述:函數
閉包有三種形式:spa
1. 全局函數是一個有名字但不會捕獲任何值的閉包。orm
2. 嵌套函數是一個有名字並能夠捕獲到其封閉函數域內的值的閉包。ip
3. 閉包表達式是一個利用輕量級語法所寫的,能夠捕獲其上下文中變量或常量值的匿名閉包。ci
今天,咱們要討論的是第三種形式,尤爲討論它是如何將繁複的、可讀性比較差的業務邏輯代碼壓縮成高可讀性、簡明明瞭的形式。文檔
你們還記得數組的map方法麼?它的參數就是一個閉包,它會將數組裏的每個元素放在閉包中進行處理,而後返回一個新的數組,甚至是與原數組不一樣元素類型的新數組。
map函數的原型以下:
func map<U>(transform: (T) -> U) -> [U]
咱們能夠看到該函數使用了泛型。(T) -> U是一個泛型閉包,它的意思就是類型T將會在閉包中進行邏輯處理,而後返回U類型。最後map函數會返回一個U類型的數組。
用一個例子來講明。今天我辦生日聚會,要迎接不少人,而且爲每一個人都準備了一句歡迎詞。咱們要怎麼作呢?首先咱們將迎接的人放進一個數組名叫guestList,而後用一個名叫greetPeople的函數爲每一個人生成歡迎詞:
func greetPeople(person: String) -> String
{
return "Hello, \(person)!"
}
let guestList = ["Chris", "Jill", "Tim"]
let fullGreetings = guestList.map(greetPeople)
而後將greetPeople函數做爲guestList數組的map函數的參數傳入,並返回一個新的數組fullGreetings,這個數組就包含了每一個人的歡迎詞。
若是咱們想展現一下每一個人的歡迎詞,咱們甚至能夠這樣寫:
fullGreetings.map(println)
這時也許有人要質疑了,println函數不是沒有返回值麼?那麼map函數會返回什麼呢?其實每個沒有返回值的函數,都會返回一個空的元組(tuple),因此說上述代碼的返回值實際上是Array<()>。
上面的例子中咱們就是將一個全局函數greetPeople做爲一個閉包來使用的。
簡明扼要的閉包表達式
其實Swift已經爲咱們提供了不少簡化的語法,可讓咱們保證代碼的高可讀性和維護性。還用上面的例子來講明,對於greetPeople這個全局函數來講,其實只須要使用一次,因此咱們不必單獨定義這個函數。咱們能夠直接使用閉包表達式來處理:
let fullGreetings = guestList.map({(person: String) -> String in return "Hello, \(person)!"})
閉包表達式實際上是函數的字面值,官方通常稱之爲匿名函數。通常當咱們須要使用函數快速的實現一個簡短的處理邏輯而且只使用一次的時候,咱們能夠省去函數名,使用簡化的語法。上面的代碼中能夠看到關鍵字in以前是閉包表達式的參數和返回值,in以後是閉包表達式實際處理邏輯的代碼區域。
下面咱們將使用Swift更多的特性來進一步簡化閉包表達式。
咱們知道Swift中有類型推斷的特性,因此咱們能夠取掉參數類型:
let fullGreetings = guestList.map({(person) -> String in return "Hello, \(person)!" })
像咱們示例中的這種單一閉包表達式,編譯器能夠根據in以前的返回值類型和return以後的返回數據類型自動判斷,因此咱們能夠省略返回值和return關鍵字:
let fullGreetings = guestList.map({person in "Hello, \(person)!" })
其實在Swift中還提供了參數的簡寫方式:$0表明第一個參數、$1表明第二個參數以此類推。因此咱們又能夠將參數名稱省略:
let fullGreetings = guestList.map({ "Hello, \($0)!" })
當函數的最後一個參數是閉包時,能夠將閉包寫在()以外,這也是Swift的一個特性,因此咱們還能夠繼續簡化:
let fullGreetings = guestList.map(){ "Hello, \($0)!" }
當函數有且僅有一個參數,並該參數是閉包時,不但能夠將閉包寫在()外,還能夠省略():
let fullGreetings = guestList.map{ "Hello, \($0)!" }
到目前爲止,示例中的閉包表達式已經被咱們根據Swift的特性,簡化爲簡明扼要、高可讀性的閉包表達式了,是否是很酷呢!