(日本語に翻訳させるのは可能です)
最近的專案開始都用 Swift 開發,在用 closure 用的很兇的情況下,有意無意間發現一些可以省略掉的一些符號
這篇文章會以最簡單的範例,逐步說明什麼情形下可以省略。
Closure 的基本知識
這裡不講太詳細,詳細的定義可以參考 [官方的文件] 。
Swift 的 closure "約等於" Objective-C 的 block ,不過運作的原理有些不同,也可以看 [這篇文章] 參考。
實務上常應用的地方例如:發送網路 request 取得 responsed 的資料、多線程編程( multithread or using GCD )等等。
基本的樣子如下:
{ ([parameters, …]) -> ([return type]) in
}
Closure 是由左大括號 {
開始、 ->
箭頭的左邊是會傳入 closure 的參數,右側則是在 closure 內部會回傳的資料型別;最後面加上 in
這個關鍵字後,用右大括號 }
關閉即算完成。
Closure 的基本用法
假如我們有個 method 叫做 signUpEmail
, 他可傳入兩個參數,一個參數需要傳入一個 String 物件 ,第二個參數是傳入一個 closure ,實作長這個樣子
func signUpEmail(email: String?, handler: (result: Bool) -> () = { _ in}) {
// 實作內容省略
handler(result: true)
}
最原始的呼叫方式
signUpEmail("demo@email.com", handler: { (result) -> () in
// ...
})
第一 - 當 closure 在最後一個參數的位置的時候,可以移到放參數的小括號的外面
這是 closure 與生俱來的能力,有這個能力之後,讓使用 closure 的語法上也更加簡潔漂亮:
signUpEmail("myemail") { (result) -> () in
// ...
}
當參數只有 Closure 自己的時候
當 method 的實作變成這樣,只有一個 closure 需要傳入
func signUpWithoutEmail(handler: (result: Bool) -> () = { _ in}) {
handler(result: true)
}
我知道! closure 可以移到外面去!
signUpWithoutEmail() { (result) -> () in
// ...
}
第二 - 當除了 closure 本身沒有其他參數時,小括號可省略
所以就變成這樣了
signUpWithoutEmail { (result) -> () in
// ...
}
當 closure 的範圍裡面不需要 return 時
第三 - -> ()
可以省略
於是就變成這樣了,就像宣告 func
一樣,不需要回傳值 (Void
) 的情形之下,就可以不用寫這個符號
signUpWithoutEmail { (result) in
// ...
}
第四 - 傳入值只剩下參數時,包起來的括號可以一併省略
還有留個括號會不會覺得醜醜的呢?
當沒有回傳的必要之後,連小括號也可以省略了
signUpWithoutEmail { result in
// ...
}
真的越來越乾淨了!
第五 - 當傳入的值是 tuple 時
改一下 method 的定義,這次多傳一個 message 進入 closure 中:
func signUpAndGetMessage(handler: (result: Bool, message: String?) -> () = { _ in}) {
handler(result: true, message: "Welcome!")
}
使用的時候,從將 closure 移出小括號開始,逐步省略如下:
signUpAndGetMessage { (result, message) -> () in
// ...
}
把回傳值省略:
signUpAndGetMessage { (result, message) in
// ...
}
到最後一個省略,就是連 tuple 本身的小括號也可以省略:
signUpAndGetMessage { result, message in
// ...
}
這樣就連使用 tuple 的時候也可以乾乾淨淨了。
當 closure 範圍裡面不用接參數、也不用 return 的情形
碰到最常使用的情形就是用 GCD 的 function ,如下:
dispatch_async(dispatch_get_main_queue()) { () -> Void in
// ...
}
這段程式碼是可以幫我們把 closure 裡面的 statements, 在 main queue 裡面執行。
可以注意到 closure 中 in
的前面有著 "() -> Void
" ,
代表著 「我不傳入數值、你也不用回傳數值」
第六 - 當不會用到的變數,我可以用底線 _ 代替
這是 Apple 讓 Swift 與生俱來可以這樣做的,結果如下:
dispatch_async(dispatch_get_main_queue()) { _ in
// ...
}
但是這樣還不夠漂亮耶,我都不需要用到,所以是不是可以不用寫他?
第七 - 可以,連 in
都可以不用寫!
dispatch_async(dispatch_get_main_queue()) {
// ...
}
我相信到這邊就已經是 closure 的最簡化了。
結語
這篇只有提到 closure 的省略寫法。如果您也是從 Objective-C 一路走來的開發者,就會發現語法上比 block 這個玩意漂亮太多了
除了漂亮之外,由於可以省略掉不需要用到的符號,在使用上也更加容易閱讀、不容易受到干擾。
當然,實務上要在團隊中開發的時候,請遵照各個團隊的 style guide ,再取得共識該怎麼省略才是比較適合的做法。
最後,如果這篇文章有幫助到你了解 Swift, closure (and so on ...) ,請幫我 Stock 收藏起來,以及分享出去,謝謝。
環境
本文範例在: Mac OS X 10.11
, Xcode Version 7.2 (7C68)
, Swift 2.1.1
, Playground
下執行順利,如果有什麼問題請在下方留言,謝謝。