Kotlin - ラムダ式

公開日:2019-11-06 更新日:2019-11-06
[Kotlin]

1. 概要

ラムダ式とは、無名関数をさらにシンプルにしたようなものです。
関数の引数をラムダ式にすることで、関数の処理の一部を外部に任せることができます。
{ 引数1 -> 式 }

{ 引数1:型, ... , 引数n:型 -> 
  処理
  処理
  戻り値
}


2. 基本

コレクションの forEach() はラムダ式や無名関数を引数として受け取ります。
実行すると、リストの各要素をラムダ式の引数として、ラムダ式を実行します。
以下の例では、ラムダ式が5回実行されます。
メソッドの引数は ( ) 内に指定しますが、ラムダ式の場合は ( ) を省略できます。
ラムダ式の引数が1つの場合は引数を省略できます。その場合の引数は it になります。
val lst = listOf(1, 2, 3, 4, 5)
lst.forEach {
    print(it)
} //12345

上記を省略しないで書くと以下のようになります。
val lst = listOf(1, 2, 3, 4, 5)
lst.forEach({n:Int ->
    print(n)
}) //12345

戻り値を返す時は、変数かリテラル値を書くだけです。return は不要です。
return をすると、ラムダ式からではなく、親の関数から抜けるので要注意です。
val lst = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val lst2 = lst.filter {
    val result = (it % 2 == 0)
    result // 戻り値。return は不要
}
println(lst2) // [2, 4, 6, 8, 10]


3. 引数が複数のラムダ式

他の言語では引数を ( ) で囲む場合がありますが、
kotlin は ( ) で囲むとエラーになるので注意してください。
val add = { v1:Int, v2:Int -> v1 + v2 }
println( add(1, 2) ) // 3


4. ラムダ式を関数の引数にする

ラムダ式を関数の引数にする場合は、引数に関数の型を定義します。
この時の引数は ( ) で囲む必要があるので要注意です。
また、引数の最後にラムダ式を指定する場合は、ラムダ式を ( ) の外に定義できます。

fun calc(v1:Int, v2:Int, f:(Int, Int) -> Int):Int {
    return f(v1, v2)
}

//左辺と右辺のどちらかで型がわかる場合は、型の省略が可能です
val add1:(Int, Int) -> Int = { v1:Int, v2:Int -> v1 + v2 }
val add2:(Int, Int) -> Int = { v1, v2         -> v1 + v2 }
val add3                   = { v1:Int, v2:Int -> v1 + v2 }
//val add4 = { v1, v2 -> v1 + v2 } //型推論できないためエラー

println(calc( 1, 2, add1)) // 3
println(calc( 1, 2, add2)) // 3
println(calc( 1, 2, add3)) // 3
println(calc( 1, 2, { v1, v2 -> v1 + v2 } )) // 3

//引数の最後にラムダ式を指定する場合は、( ) の外に定義できます
println(calc(1, 2) {
    v1, v2 -> v1 + v2 }
) // 3


5. ラムダ式で return

ラムダ式の途中で return したい場合は、「return@親の関数名」か「return@ラベル」とします。

「return@親の関数名」で抜ける
val list1 = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val list2 = list1.filter{
    if (it > 6) return@filter false

    it % 2 == 0
}
println(list2) // [2, 4, 6]

「return@ラベル」で抜ける
val list1 = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val list2 = list1.filter test@ {
    if (it > 6) return@test false

    it % 2 == 0
}
println(list2) // [2, 4, 6]


6. ブロック不可

他の言語では { } でブロックにして、ローカル変数の重複を避けることができますが、
kotlin では、ラムダ式として扱われます。

以下の場合、test() 内のブロックはラムダ式として扱われるため、何も処理されません。
fun test() {
    {
        println("test")
    }
}
test()

ラムダ式の後ろに ( ) を付けるとその場で実行できるため、それを利用してブロックのように使うことはできます。
但し、書き方によっては、文末に「;」セミコロンを付けないとコンパイルエラーになるため、要注意です。
fun test() {
    val a = 1
    val b = 2
    var c = 0
    {
        val a = 100
        c = a + b
    }( )
    println(c); // 102。「;」をはずすとエラーになる

    {
        c = a + b
    }( )
    println(c) // 3
}

test()