Swift さくっと確認したい基礎文法 [クロージャ(closure)]


# クロージャ(closure)

一言で言えば、名無しの関数式。


# 基本的な書き方

```swift
{(引数:引数の型) -> (戻り値の型) in
    // 処理
	return 戻り値
}
```


```swift

// a + b を足した結果を返すクロージャをaddFuncに代入
let addFunc = {(a:Int, b:Int) -> Int in
    return a + b
}

let result = addFunc(1,2)
println(result)  // 3

```

戻り値が一つの場合は、上のように`()`を省略できます。


クロージャを型推論でaddFuncに代入しましたが、
型をきちんと指定すると下記のようになります。

```swift
let addFunc: (Int,Int) -> Int = {(a:Int, b:Int) -> Int in
    return a + b
}
```

Intの引数が二つ、戻り値がInt一つの関数の型と同じです。

※ちなみに引数も戻り値もない場合は下記のように書きます。

```swift
var simpleClosure = {() -> () in
    var a = 1+1
    println(a) // 2
}
```


# 引数にクロージャをとる関数

## map()関数

第一引数に指定した配列のすべての値に対して
クロージャで指定した処理を実行します。

```swift
map(配列, クロージャ)
```

```swift
let numbers = [0.02,0.4,0.26,0.8]

// 指定した配列内の数値一つずつをパーセンテージ化
let array = map(numbers, { (let num:Double) -> String in
    var percent = num*100
    return percent.description + "%"
})

// [2.0%, 40.0%, 26.0%, 80.0%]
println(array) 
```


下記のように、第二引数のクロージャを外に出す書き方もできます。

```swift
let array = map(numbers){(let num:Double) -> String in
    var percent = num*100
    return percent.description + "%"
}
```

型推論で型宣言を省略し、returnも省略すると
下記のようになります。

```swift
let array = map(numbers){num in (num*100).description + "%"}
```

１行で書くことができ、かなりスッキリとした印象です。

さらに...
クロージャの引数は`$0,$1,$2` : 第1引数の値,第2引数の値,第3引数の値
というように指定することができます。

今回の場合は下記のように書くことができます。

```swift
// 第一引数を$0(上の式でいうnum)として処理
let array = map(numbers){($0*100).description + "%"}
```

ただあまり省略すると可読性が下がるので、
ほどほどにしたほうがよさそうです。


## sorted()関数
Stringや配列の値を大きさによってソートする関数です。

```swift
sorted(配列, クロージャ)
```


### Array\<String\>の場合(String()[])

下の例は、
String型の配列をabc順に並び替えています。
※`.uppercaseString`で大文字に変換して並び替えしています。

```swift
var cafeMenu: Array<String>
cafeMenu = ["Coffee","cappuccino","Latte","mocca"]

let sortedCafeMenu = sorted(cafeMenu, {(s1:String,s2:String) -> Bool in
    return (s1.uppercaseString < s2.uppercaseString)
})
println(sortedCafeMenu)

```
```swift:出力
"[cappuccino, Coffee, Latte, mocca]"
```


#### 省略1

```swift
var cafeMenu: Array<String>
cafeMenu = ["Coffee","cappuccino","Latte","mocca"]

let sortedCafeMenu = sorted(cafeMenu, {(s1,s2) -> Bool in
    return (s1.uppercaseString < s2.uppercaseString)
})
println(sortedCafeMenu)

```

#### 省略2

```swift
var cafeMenu: Array<String>
cafeMenu = ["Coffee","cappuccino","Latte","mocca"]

let sortedCafeMenu = cafeMenu.sorted {
    $0.uppercaseString < $1.uppercaseString
}
println(sortedCafeMenu)

```

### Dictionary\<String,Int\>()の場合(Dictionary\<String,Int\>())

以下のようにしてDictionary型も並び替えができます。

#### String(メニューのabc順)で並び替え

```swift
var menuDictionary = Dictionary<String,Int>()
menuDictionary = ["Coffee":300,"cappuccino":400,"Latte":400,"mocca":450]

let sortedMenuDictionary = sorted(menuDictionary,{(d1:(String,Int),d2:(String,Int)) -> Bool in
    return d1.0.uppercaseString < d2.0.uppercaseString
})

println(sortedMenuDictionary)
```
```swift:出力
"[(cappuccino, 400), (Coffee, 300), (Latte, 400), (mocca, 450)]"
```

#### Int(値段順)で並び替え

```swift
var menuDictionary = Dictionary<String,Int>()
menuDictionary = ["Coffee":300,"cappuccino":400,"Latte":400,"mocca":450]

let sortedMenuDictionary = sorted(menuDictionary,{(d1:(String,Int),d2:(String,Int)) -> Bool in 
    return d1.0.uppercaseString < d2.0.uppercaseString
})

println(sortedMenuDictionary)
```
```swift:出力
"[(Coffee, 300), (Latte, 400), (cappuccino, 400), (mocca, 450)]"
```

# クロージャを受け取る関数

クロージャは関数の引数としても利用できます。
下の例では、関数`dicMap()`の引数はDictionaryとクロージャです。

`dicMap()`関数内で、
Dictionaryの値をクロージャに渡して、結果を返すということをしています。

今回の例は、
ある商品リストの価格を、
クロージャで税込み価格にして返すという処理をしています。

```swift
// メニューのDictionary
var menuDictionary = ["Coffee":300.0,"cappuccino":400.0,"Latte":400.0,"mocca":450.0]

// 税込み価格を返すクロージャ
var getIntaxPrice = {(name:String, value:Double) -> (String,Double) in
    return (name,value*1.08)
}

// メニューのDictionaryを受け取って、税込み価格に変換したDictionaryを返す関数
func dicMap(var dic:Dictionary<String,Double>, closure:(String,Double) -> (String,Double)) -> Dictionary<String,Double> {
    
    for (key, value) in dic {
        println(value)
        let(theKey, newValue) = closure(key,value)
        dic[theKey] = newValue
    }
    return dic
}

// 税込み価格のメニュー
let inTaxMenuDictionary = dicMap(menuDictionary,getIntaxPrice)

println(inTaxMenuDictionary)
```
```swift:出力
[Coffee: 324.0, Latte: 432.0, mocca: 486.0, cappuccino: 432.0]
```

# クロージャ間で値を保持する

関数内にクロージャを宣言する場合、
関数内のクロージャの外に宣言した変数の値を保持することができます。
staticなローカル変数と同じ扱いです。

```swift
func hp(max:Int) -> (Int) -> Int {
    
    // 保持される変数
    var nowHp = max
    
    func attacked(damage:Int) -> Int {
        if nowHp > damage{
            nowHp -= damage
        } else {
            nowHp = 0
        }
        return nowHp
    }
    return attacked
}
let hp100 = hp(100) // 100

var restHp = hp100(30)
println(restHp) // 70(100-30)
restHp = hp100(40)
println(restHp) // 30(70-40)
restHp = hp100(50)
println(restHp) // 0(30-50)
```

呼び出すごとに返ってくる値が小さくなっています。
関数内の値が保持されている証拠です。