【Swift Closure】読み方・書き方をキホンから学ぶ

# この投稿について
この投稿は投稿者の覚書を主な目的としているので、読みづらい部分があるかもしれません...。

### 誰のため？
- Swift のクロージャ(Closure) を基本から理解したい人
- 関数や制御構文について理解できている

### 実行環境
- Swift4.2
- Xcode10 (Playground)
- macOS Mojave

## 関数を閉じ込める
あらかじめ定義した関数は、別の関数に引数として渡せました。
関数は、変数オブジェクトや定数オブジェクトにまるごと格納することもできます。
通常の関数定義はこのような記述でした。

```swift: 
func sayHelloIn(loud isLoud: Bool) {
    var message = "hello"
    if isLoud {
        message = message.uppercased() + "!!"
    }
    print(message)
}

sayHelloIn(loud: true)
```

関数をオブジェクトに代入

```swift:
let sayHello = sayHelloIn
sayHello(false)
```

代入して使うなら、関数名を定義する必要なかった
使える名前が減ってしまう
名前を考える時間がもったいなかった
関数名を使わずに、オブジェクトに代入する方法がある
 
通常の関数定義と比較しながら、関数をオブジェクトに格納してみましょう。
定数オブジェクト `hello` に、関数を格納します。
まずは、`{}` でコードブロックを作成します。


```swift:
let hello = {}
```
 
コードブロック内に、`seyHelloIn()` 関数のデータ型を記述しましょう。
引数 `isLoud` は `Bool` 型です。
この関数に返り値はありません。
Swift では、返り値がないことを `Void` と表現します。
引数がない場合は、単に `()` の中が空欄になります。
 
```swift:
let hello =  { (isLoud: Bool) -> Void }
```
 
関数のデータ型を記述できました。
データ型の直後には、`in` キーワードを記述します。
関数で行いたい処理は `in` キーワード後に記述します。

```swift:
let hello = { (isLoud: Bool) -> Void in
    var message = "hello"
    if isLoud { message = massege.uppercased() + "!"
    print(message)
 }
```
 
`in` キーワードの手前がデータ型で、`in` キーワード以降が処理内容ですね。
これらが、`{}` コードブロックでまとめられています。
コードブロックごと定数オブジェクトに代入します。

これで、関数をオブジェクトに格納できました。
格納されたオブジェクトは、どんなデータ型になっているでしょうか。
クイックリファレンスで確認しましょう。
Declaration には、`(Bool) -> Void` という表示されています。
この「カッコで括られた引数の型、矢印、返り値の型」が、関数のデータ型になります。
引数は、カンマで区切って列挙することもできます。
「コードブロック内に、関数のデータ型 `in` 実装」という構造になっています。
実行してみましょう。

```swift:
hello(true)
hello(false)
```

オブジェクトに格納された関数を実行するには、オブジェクト名の後に `()` をつけます。
引数がある場合は、`()` に指定できます。


関数に引数がない場合は、コードブロックの後に `()` をつけて実行結果を直接、オブジェクトに格納することもできます。

```swift:
let bigHello = { ( ) -> String in
    let message = "Hey!".uppercased()
    return message
}()
```
 
定数オブジェクト `bigHello` をコンソールに出力してみます。
関数の実行結果である `"HEY!"` が表示されていますね。

```swift:
print(bigHello)
```


このように、`{}` を使って処理をまとめる記述方法を __クロージャ(Closure)__ と言います。

## 友達リストを絞り込む
引数として関数を渡すケースをもう少し詳しく見てみましょう。
`frends` は友達のリスト

```swift:
 let myFriends = ["Anny", "Dan", "Billy", "Adam","Rick", "Anthony","Erick", "Alex"]
 ```

`filteredNames(friends:condition:)` 関数は...
友達リストから、「特定の条件」に該当する名前の配列を返す。
`filteredNames(friends:condition:)` 関数の第2引数に注目します。
この2つ目の引数が「特定の条件」になっている（データ型は `(String)->Bool` ）

```swift:
/*                                         ↓ 引数になってる「特定の条件」          */
func filterNames(_ friends: [String], _ condition: (String) -> Bool) -> [String] {
    var filteredNames = [String]()
    for name in friends {
        if condition(name) { filteredNames.append(name) }
    }
    return filteredNames
}
```


第2引数には、`(String) -> Bool` な関数ならなんでも渡すことができます。
`startingWith()` 関数という「特定の条件」を調べる関数を渡すことにします。
この関数は、名前の一文字目が `"A"` と一致するかを調べます。
 

```swift:
func startingWithA(_ name: String) -> Bool {
    return name.hasPrefix("A")
}
```

特定の条件をいちいち関数に定義して実装するのは、面倒臭いですね。
実は、`filterNames()` 関数の呼び出しで引数を指定するときに直接、条件を記述できます。
この関数を、クロージャで記述してみると...。

```swift:
let conditionClosure = { (name: String) -> Bool in
    return name.hasPrefix("A")
}
````

`filterNames()` 関数の `2` つ目の引数は、`(String) ->Bool` 型でした。
引数として渡す関数をクロージャにできたら、コードブロック `{}` ごと引数に記述します。
 
`{}` の中に、関数のデータ型を明示します。
引数は `String` 型のオブジェクト `name`
返り値として `Bool` 型を指定します。

```swift:
{ (name: String) -> Bool }
```

`in` キーワードの後に実装を記述します。
実装には、接頭文字が "A" かどうかの結果を返すようにします。

```swift:
 { (name: String) -> Bool in return name.hasPrefix("A") }
```
 
「関数はクロージャにすれば、関数の引数に記述できる」ということがわかりますね。
実行してみましょう。
結果を格納する `result` オブジェクトを宣言しておきます。
コンソールに `result` を出力すると、正しく機能していることがわかりますね。

```swift:
let result = filterNames(myFriends, {(name: String) -> Bool in return name.hasPrefix("A") })
print("名前がAではじまる友達", result)
```

## ショートハンド
直接、条件を記述できるようになったのはいいことですが、今度は関数の呼び出しコードが長ったらしくなった
そんな場合は、クロージャの省略記法（ショートハンド）
省略できる箇所を一つずつ見ていきましょう。
まず、引数のデータ型です。
 `filgerName(friends:condition)` 関数の定義によって、2つめの引数は `(String)->Bool` 型と推論されるので `:String` が省略可能です。

```swift:
/*                                           : String を省略した */
/*                                              ↓              */
let result_1 = filterNames(myFriends, {(name        ) -> Bool in return name.hasPrefix("A") })
```
 
また、引数が一つの場合は、それを括る `()` も省略可能です。

```swift:
/*                                        (            ) を省略した    */
/*                                        ↓            ↓             */
let result_2 = filterNames(myFriends, { name          -> Bool in return name.hasPrefix("A") })
```

さらに、` retrun` キーワード以降が条件式になっているので、返り値が `Bool` 型であることが決定しています。
 `filterNames(friends:condition)` 関数の定義によって推論されているのではないことに注意しましょう。
 `-> Bool` も省略します。

```swift:
/*                                                     -> Bool を省略した */
/*                                                         ↓             */
let result_3 = filterNames(myFriends, { name                  in return name.hasPrefix("A") })
```

`in` キーワード以降が `1` 行だけなら、`return` も省略できます。

```swift:
/*                                                                  return を省略した
                                                                    ↓    */
let result_4 = filterNames(myFriends, { name                  in        name.hasPrefix("A") })
```



```swift:
let result_1 = filterNames(myFriends, {(name        ) -> Bool in return name.hasPrefix("A") })
let result_2 = filterNames(myFriends, { name          -> Bool in return name.hasPrefix("A") })
let result_3 = filterNames(myFriends, { name                  in return name.hasPrefix("A") })
let result_4 = filterNames(myFriends, { name                  in        name.hasPrefix("A") })
```

ここまでシンプルに記述できました。
パッと見で、`{ name in name.hasPrefix("A") }` は、第2引数であると理解できるでしょうか？

```swift:
let result_5  = filterNames(myFriends, { name in name.hasPrefix("A") })
```

ずいぶんスッキリみえるようになりましたが、`()` の括りがちょっとわかりづらいですね。
`filterNames(friends:condition)` 関数を第1引数 `friends` で閉じて、第2引数である関数は、コードブロックとして分離できます。

```swift:
/*                                                         ここにあった ) が...
                             こっちに移動して                           ↑
                                   ↓                                 ↑   */
let result_6 = filterNames(myFriends) { name in name.hasPrefix("A") }
/*                                  ↑
                                    , がなくなった                    */
```


これなら `filterNames(friends:condition:)` 関数の引数は、`friends` オブジェクトとコードブロックの 2 つだけということがハッキリと分かりますね。
 
もう少しだけ、省略できます。
コードブロックに注目しましょう。
引数として `name` を受けて、その `name` の接頭文字をチェックしていますが `name`が 2 つ記述されて、冗長な印象があります。
クロージャの引数名は明示しなくても `$` 記号で代替できます。
`name` は、最初の引数なので、`$0` となります。
もし、クロージャに 2 つ目の引数があれば、`$1` となります。

```swift:
/* in キーワードも不要 */
let result_7 = filterNames(myFriends) { $0.hasPrefix("B") }    
print("名前がBではじまる友達", result_7)
```

ここまで省略できれば、「特定の条件」を変更したくなっても対応はカンタンです。
例えば、`5` 文字以上の名前を集めたいとします。
`$0.` 以降を変更すればOKです。

```swift:
let result_greater5 = filterNames(myFriends) { $0.count >= 5 }
print("5文字以上の名前:", result_greater5)
```

Swift プログラミングでは、多くの場面でクロージャを駆使されています。
Swift には欠かせない機能なので、必ずマスターしましょう。