クロージャ

ここでは Swift のクロージャ (closures) について学びます。

Swift でのクロージャは主に三つの形式があります。ひとつはグローバル関数 (global functions)。 これは名前付きで、値をキャプチャしないクロージャといえます。二つ目はネストされた関数 (nested functions)。 これは名前付きで、関数を包含するブロックにおける値をキャプチャするクロージャです。

これらは普通に関数と呼ばれるもので、特別な形式のクロージャといえます。

三つ目はクロージャ式 (closure expressions) です。

これは名前無し、かつ、そのコンテキストにおける値をキャプチャするものです。 このページでは三つ目のクロージャ式について説明します。

クロージャ式

クロージャ式 は次の形式で記述できます。

{ (引数1: 型1, 引数2 : 型2, ...) -> 戻り値の型 in
	return 戻り値
}

具体例を取り上げて説明します。

配列の sort 関数は、「配列の二つの要素を受取り、一つめの引数と二つめの引数がソートしたい順序にあるときに True、そうでない場合に False を返す関数」 を引数として受取ります。

func f( i : Int, j : Int ) -> Bool {
	return i > j
}

var nums = [ 3, 10, 1, 5, 2 ]

nums.sort( by: f )
print( nums )

実行結果

[10, 5, 3, 2, 1]

ちなみに > 演算子は上の関数 f と同様に定義されます。このため、上のソートに関しては次のようにシンプルに書けます。

var nums = [ 3, 10, 1, 5, 2 ]
nums.sort( by: > )
print( nums )

ここでは一般論としてクロージャの性質をみていきます。

ここで関数名の f というのは全く重要ではありませんので、名前無しのクロージャ式で記述してみましょう。 クロージャ式を使うと次のように書けます。

var nums = [ 3, 10, 1, 5, 2 ]

nums.sort( by: { ( i : Int, j : Int ) -> Bool in
	return i > j
} )

print( nums )

一行で終わるときは in の後で改行する必要は無いので、改行をやめると次のようになります。

nums.sort( by: { ( i : Int, j : Int ) -> Bool in return i > j } )

コードはかなり短くなりましたね。

さらに、nums は Int の配列なので、クロージャ内で記述している Int という型はわかりますので省略できます。さらに、return は比較した結果 (True または False) を 返しているのでこれも Bool しかなりえず型がわかります。

このように全て型がわかる場合は、型の指定も省略できます。すると上記の記述は次のようになります。

nums.sort( by: {  i , j in return i > j } )

さらに、単一の式で表されるクロージャでは、暗黙的にその値が返るので return も省略できます。したがって、次のようになります。

nums.sort( by: {  i , j in i > j } )

Swift ではインラインクロージャでは自動的に引数の省略名が作成されます。最初の引数から $0, $1, $2, ... という調子です。

これを利用すると、上記の i, j という宣言も不要となり、次のようになります。

nums.sort( by: { $0 > $1 } )

始めの書き方と比較すると、圧倒的に記述が短く簡潔になりましたね。

トレーリング・クロージャ

関数のパラメータリストの最後にクロージャ式が引数となっているときは、そのクロージャ式を関数呼び出しの後に続けて書くことができます

例えば、先の sort の例では、クロージャ式が唯一の (よって、最後の) 引数です。従って、クロージャを外に出して次のように書けます。

nums.sort() { $0 > $1 }

このように関数の後に続けて記述したクロージャを、トレーリング・クロージャ (trailing closures) といいます。

クロージャの本体の記述が長くなる場合には、このように記述したほうが可読性が上がる場合があります。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Swift による iOS 開発入門