~個人メモ~ [swift] 関数・クロージャの基本的な仕様について 

※この記事はswift学習中の筆者のノートです。

ちょっと振り返りたい時に、都度本(swift実践入門)を開いて該当ページを探すのがめんどくさかったので簡単に纏めました。

## 関数
### 関数とは
"名前を持ったひとまとまりの処理"のことで、外部から処理を呼び出し実行することができる機能のことをいう。

### 定義方法
関数はfuncキーワードで宣言、そして関数名、引数、戻り値の型、文を定義する

```swift
func 関数名(引数名1: 型, 引数名2: 型, ...) -> 戻り値の型 {
  関数呼び出し時に実行される文
  必要に応じてreturn文で戻り値を返却
}
```

例：数値を２倍する関数

```swift
func double(number x: Int) -> Int {
    return x * 2
}

double(number: 150)      // 300
```

### 引数について
#### 仮引数と実引数

- 関数の定義時に宣言するもの・・・`仮引数`
- 関数の呼び出し時に指定するもの・・・`実引数`

```swift
func printInt(_ int: Int) {
    print(int)
}
// 関数の定義時に宣言している'int'が仮引数

printInt(1)
// 関数の呼び出し時に指定している'1'がが実引数
```

#### 外部引数名と内部引数名

- 外部からの呼び出し時に使用するもの・・・`外部引数名`
- 関数内で使用されるもの・・・`内部引数名`

```swift
func sample(外部引数名 内部引数名: 型) {
    関数の内部では内部引数名を使用する
}

sample(外部引数名: 型)
```
外部引数名は省略することもできる。
その場合は関数の定義時に(_ 内部引数名: )のように外部引数名に_を使用する。
呼び出し時には、:も省略し、値のみの記述で呼び出す。


### 可変長引数
引数定義の末尾に...を加えることでArrey型となる。
(実引数が複数あっても配列として受け取ることができる)

```swift
func printStrings(strings: String...) {    
    for string in strings {
        print("\(string)")
    }
}

printStrings(strings: "abc", "def", "ghi")
// 実行結果
// abc
// def
// ghi
```

## クロージャ
### クロージャ(closure)とは
"名前を持たないひとまとまりの処理"のこと。
特徴的なのは`名前が不要ということ`、`型推論により省略可能範囲が広いということ`、`変数に代入でき、クロージャをパラメータとして受け取ることができるということ`などが挙げられる。

### 定義方法
クロージャ式と呼ばれる、処理を{}で囲むフォーマットで`引数・戻り値の型・文`を定義する。

```swift
{ (引数名1: 型, 引数名2: 型, ...) -> 戻り値の型 in
    実行される文
    必要に応じてreturn
}
```

例：数値を２倍するクロージャ

```swift
let double = { (x: Int) -> Int in
    return x * 2
}

double(2)    // 4
```

### 型推論
決まった型にクロージャを代入する場合は、型を省略できる。

```swift
// 型を省略しない場合
let double: (Int) -> Int
    
double = { (x: Int) -> Int in
    return x * 2
}

double(2)   // 4

// 型推論により省略した場合

let triple: (Int) -> Int
    
triple = { x in
    return x * 3
}

triple(2)   // 6
```

### 実行方法
定義した定数名+()内に引数をいれ実行する。
渡された引数に対して処理が実行される。

```swift
let lengthString = { (mozi: String) -> Int in
    return mozi.count
}

lengthString("文字数を知りたい")   // 8
```

ちなみに同じ処理を関数にするとこんな感じ

```swift
func lengthString2(mozi2: String) -> Int {
    return mozi2.count
}

lengthString2(mozi2: "mozisuuwosiritai")   // 16
```

### クロージャの引数
関数の引数との違いは以下の通り

- 関数      => 外部引数名と内部引数名がそれぞれ指定できる
- クロージャ => 内部引数名のみ指定できる

すなわちクロージャの場合は()内には値のみ入るということ

また、クロージャでは`デフォルト引数も指定できない`仕様となっている。

#### 簡略引数名
クロージャでは簡略引数名を利用し、引数名の定義も省略することが可能である。
簡略引数名は$にインデックス番号をつける。
※型推論できない場合はコンパイルエラーとなる。

```swift
let array = [1,2,3,4,5]
let newArray = array.map { $0 * 5 }
// 配列の要素の１番目を $0 と表現している。
// mapメソッドの引数がクロージャ
// mapメソッドは要素を一つ一つ取り出して実行するから、取り出された要素は毎回一つ目の要素となる$0
// map( {() -> Int In return $0 * 5 } ) みたいな形が省略前の形と思う
newArray // [5, 10, 15, 20, 25]
```

### 変数と定数のキャプチャ
クロージャ自身が定義されたスコープの変数の値はreturn後も保持される.


```swift
let counter: () -> Int
do {
    var count = 0
    counter = {
        count += 1
        return count
    }
}

counter()  // 1
counter()  // 2
```

### 引数としてのクロージャ
クロージャを関数や別のクロージャとして利用する場合の仕様として、
`属性`と`トレイリングクロージャ`がある

#### 属性は２種類
クロージャの型の前に、@属性名を追記して指定する

`@escaping` 
関数に引数として渡されたクロージャが、関数のスコープ外で保持される可能性があることを示す属性
この属性が付与されているかどうかで、コンパイル時にクロージャがキャプチャを行うか判断される

`@autoclousure`
引数をクロージャで包むことで遅延評価を実現するための属性


### トレイリングクロージャ
引数のクロージャを外に出すこと。
最後の引数がクロージャの場合のみ可能。

```swift
func hoge(A: Int, B: Int, Cl: () -> Int { 
    クロージャの処理 
})
```

のような関数を呼び出したい場合。


以下、呼び出し時

```swift
//通常
hoge(A: 1, B: 5, Cl: { Print(Int) })

//トレイリングクロージャ
hoge(A: 1, B: 5) { Print(Int) }
```
と書く事ができる

引数が一つだけの場合、()も省略でき、クロージャを外にだせる。
`hoge { clouser }`みたいな形。
けっこうよく見かける形。可読性がよくなる。