LoginSignup
2
2

More than 5 years have passed since last update.

Closure 可以省略的一些東西

Posted at

(日本語に翻訳させるのは可能です)

最近的專案開始都用 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 下執行順利,如果有什麼問題請在下方留言,謝謝。

參考資料

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2