Pebble Coding

ソフトウェアエンジニアによるIT技術、数学の備忘録

swift クロージャ

swiftを久々に触ったら、クロージャの文法を完全に忘れていたので、メモしておく。

Closure Expression Syntax

クロージャはこの形をしている。

{ (parameters) -> return type in  
    statements  
}  

例えば、このように使う。

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]  

reversed = names.sort( { (s1: String, s2: String) -> Bool in return s1 > s2 } )  

Inferring Type From Context

sortメソッドの引数に渡せるクロージャの型は決まっており、コンパイラが引数や戻り値を推測するため、 クロージャでは引数や戻り値の型を省略できる。
「戻り値の型を省略した場合、引数を囲むカッコ()は省略できる。」
ので、このように書ける。

reversed = names.sort( { s1, s2 in return s1 > s2 } )  

戻り値が一つの場合はreturnも省略できる。

reversed = names.sort( { s1, s2 in s1 > s2 } )  

Shorthand Argument Names

クロージャでは簡易引数表現が使える。
$0は1番目の引数、$1は2番目の引数を表す。

reversed = names.sort( { $0 > $1 } )  

Trailing Closures

関数の最後の引数としてクロージャを渡す場合、関数に渡すクロージャ文をカッコの外に記述することができる。
次のように書ける。

reversed = names.sort() { $0 > $1 }  

クロージャをカッコ外に記述した結果、それ以外の引数がない時は、残ったカッコ()は省略することができる。

reversed = names.sort { $0 > $1 }  

Capturing Values

値のキャプチャ
以下を考える。

func makeIncrementer(forIncrement amount: Int) -> () -> Int {  
    var runningTotal = 0  
    func incrementer() -> Int {  
        runningTotal += amount  
        return runningTotal  
    }  
    return incremented  
}  
  
let incrementer_even = makeIncrementer(forIncrement: 2)  
  
let val1 = incrementer_even() // 2  
let val2 = incrementer_even() // 4  
let val3 = incrementer_even() // 6  

makeIncrementerは関数を戻り値として返す関数である。

値のキャプチャという分かりづらい表現で説明されているが、C++でいうところのrunningTotalという状態変数を持つ関数オブジェクト(ファンクタ)と同じ機能だと考えた方が分かりやすい。
runningTotalという状態変数はincremented_evenのインスタンスが解放されたタイミングで解放される。