Closure 可以省略的一些東西


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

最近的專案開始都用 Swift 開發，在用 closure 用的很兇的情況下，有意無意間發現一些可以省略掉的一些符號

這篇文章會以最簡單的範例，逐步說明什麼情形下可以省略。

# Closure 的基本知識

這裡不講太詳細，詳細的定義可以參考 [[官方的文件](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html)] 。

Swift 的 closure "約等於" Objective-C 的 block ，不過運作的原理有些不同，也可以看 [[這篇文章](http://qiita.com/vc7/items/0ca42b5a7faee7952254)] 參考。

實務上常應用的地方例如：發送網路 request 取得 responsed 的資料、多線程編程（ multithread or using GCD ）等等。

基本的樣子如下：

``` text
{ ([parameters, …]) -> ([return type]) in
}
```

Closure 是由左大括號 `{` 開始、 `->` 箭頭的左邊是會傳入 closure 的參數，右側則是在 closure 內部會回傳的資料型別；最後面加上 `in` 這個關鍵字後，用右大括號 `}` 關閉即算完成。

# Closure 的基本用法

假如我們有個 method 叫做 `signUpEmail`, 他可傳入兩個參數，一個參數需要傳入一個 String 物件  ，第二個參數是傳入一個 closure ，實作長這個樣子

``` swift
func signUpEmail(email: String?, handler: (result: Bool) -> () = { _ in})  {
    // 實作內容省略
    handler(result: true)
}
```

## 最原始的呼叫方式

``` swift
signUpEmail("demo@email.com", handler: { (result) -> () in
    // ...
})
```

### 第一 - 當 closure 在最後一個參數的位置的時候，可以移到放參數的小括號的外面

這是 closure 與生俱來的能力，有這個能力之後，讓使用 closure 的語法上也更加簡潔漂亮：

``` swift
signUpEmail("myemail") { (result) -> () in
    // ...
}
```

## 當參數只有 Closure 自己的時候

當 method 的實作變成這樣，只有一個 closure 需要傳入

``` swift
func signUpWithoutEmail(handler: (result: Bool) -> () = { _ in})  {
    handler(result: true)
}
```

### 我知道！ closure 可以移到外面去！

``` swift
signUpWithoutEmail() { (result) -> () in
    // ...
}
```

### 第二 - 當除了 closure 本身沒有其他參數時，小括號可省略

所以就變成這樣了

``` swift
signUpWithoutEmail { (result) -> () in
    // ...
}
```

## 當 closure 的範圍裡面不需要 return 時

### 第三 - `-> ()` 可以省略

於是就變成這樣了，就像宣告 `func` 一樣，不需要回傳值 (`Void`) 的情形之下，就可以不用寫這個符號

``` swift
signUpWithoutEmail { (result) in
    // ...
}
```

### 第四 - 傳入值只剩下參數時，包起來的括號可以一併省略

還有留個括號會不會覺得醜醜的呢？

當沒有回傳的必要之後，連小括號也可以省略了

``` swift
signUpWithoutEmail { result in
    // ...
}
```

真的越來越乾淨了！

### 第五 - 當傳入的值是 tuple 時

改一下 method 的定義，這次多傳一個 message 進入 closure 中：

``` swift
func signUpAndGetMessage(handler: (result: Bool, message: String?) -> () = { _ in})  {
    handler(result: true, message: "Welcome!")
}
```

使用的時候，從將 closure 移出小括號開始，逐步省略如下：

``` swift
signUpAndGetMessage { (result, message) -> () in
    // ...
}
```

把回傳值省略：

``` swift
signUpAndGetMessage { (result, message) in
    // ...
}
```

到最後一個省略，就是連 tuple 本身的小括號也可以省略：

``` swift
signUpAndGetMessage { result, message in
    // ...
}
```

這樣就連使用 tuple 的時候也可以乾乾淨淨了。

## 當 closure 範圍裡面不用接參數、也不用 return 的情形

碰到最常使用的情形就是用 GCD 的 function ，如下：

``` swift
dispatch_async(dispatch_get_main_queue()) { () -> Void in
    // ...
}
```

這段程式碼是可以幫我們把 closure 裡面的 statements, 在 main queue 裡面執行。

可以注意到 closure 中 `in` 的前面有著 "`() -> Void`" ，

代表著 「我不傳入數值、你也不用回傳數值」

### 第六 - 當不會用到的變數，我可以用底線 _ 代替

這是 Apple 讓 Swift 與生俱來可以這樣做的，結果如下：

``` swift
dispatch_async(dispatch_get_main_queue()) { _ in
    // ...
}
```

但是這樣還不夠漂亮耶，我都不需要用到，所以是不是可以不用寫他？

### 第七 - 可以，連 `in` 都可以不用寫！

``` swift
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` 下執行順利，如果有什麼問題請在下方留言，謝謝。

## 參考資料

- [The Swift Programming Language (Swift 2.1)](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html)