Kotlinのラムダ式とSwift 3.0のクロージャ式の比較

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

まえがき

ラムダ式はとっても便利。Kotlin使いなら簡単なコールバック、リスナーはいちいちinterfaceつくらず、ラムダ式で作って楽しちゃってますよね。
Swiftでも同じことをやりたい場合どうするかみてみましょう。

そもそもラムダ式とは

(厳密には正しくないが)匿名メソッドをより短く記述するための構文である。 第1回 ラムダ式 - @ITより引用

私もこのくらいの理解しかありません。。
無名関数を短くかける!っという理解で読んでいただければ、この記事では事足りると思います。

Swiftの場合は、クロージャ式があり、ラムダ式と同じように無名関数を短く書くことができます。

例題

以下の例題を実装する場合で比較してみましょう。

1.Arrayの拡張で、一つでも条件に適応しているものがあるかチェックするanyを作成する
2.Arrayの中に空文字があるかチェックする

Kotlin

// package kotlin.collectionsより引用
// ラムダが引数にある場合は、inline設定をしたほうが高速
public inline fun <T> Iterable<T>.any(predicate: (T) -> Boolean): Boolean {
    for (element in this) if (predicate(element)) return true
    return false
}

val names = listOf("Chris", "Alex", "Ewa", "Barry", "Daniella")

//何も省略しない場合。どこのreturnなのか、ラベル(@any)をつける
names.any({ name: String -> return@any name.isEmpty() })

//returnは省略可能
names.any({ name: String -> name.isEmpty() })

//型も省略可能
names.any({ name -> name.isEmpty() })

//引数が一つの場合は、itがデフォルトになる
names.any({ it.isEmpty() })

//関数の最後の引数がラムダの場合は、()を省略可能
names.any { it.isEmpty() }

ラムダ式以外に、普通の関数も渡せます。

//emptyかどうかを判定する関数
fun empty(str: String) = str.isEmpty()
//同じクラス内なら、::関数名。引数は省略します。
names.any(::empty)

Swift

//一つでも条件に適応しているものがあるかチェックするanyを作成する
//Koltinと同じような拡張を実装
extension Array {
    //fがElementを引数にBoolを返す関数型
    func any(f: (Element) -> Bool) -> Bool {
        for element in self {
            if f(element) {
              return true
            }
        }
        return false
    }
}

クロージャ式の定義

{ (parameters) -> return type in
    statements
}

The Swift Programming Language (Swift 3.0.1): Closuresより

もっと噛み砕いた表現をすると以下のようになります。

(引数: 引数の型) -> 戻り値の型

同じように、例題をやってみましょう。

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

//何も省略しない、定義通りの形
names.any(f: { (element: String) -> Bool in return element.isEmpty })

//型は推測できるため、省略可能
names.any(f: { element in element.isEmpty })

//returnは一行だけなら省略可能
names.any(f: { element in return element.isEmpty })

//指定しない場合、デフォルトで$0,$1..$nで受け取ることできる
names.any(f: { $0.isEmpty })

//最後の引数が()の場合、 ()は省略可能
names.any{ $0.isEmpty }

クロージャ式以外に、普通の関数も渡せます。

//emptyかどうかを判定する関数
func empty(string: String) -> Bool {
    return string.isEmpty
}

//関数名を指定する
names.any(f: empty)

まとめ

同じような形で実装できました。
一度しか使わないような処理はラムダ式、クロージャ式で書くと快適です。。
ラムダ式、クロージャ式はなれるとすごく読みやすいのでどんどん使っていきましょう!

参考