1. ラムダ式の構文
前回の記事を振り返ると、どこかで関数を実行する必要があるのですが、この関数のパラメーターの型と戻り値の型 (Kotlin では、パラメーターの型と戻り値の型を合わせた特別なデータ型が構成されます: 関数の型) しかわかりませんが、関数 具体的な操作は問わないので、パラメータの型と戻り値の型の条件を満たす関数を動的に渡しますが、パラメータとして渡せるのはオブジェクトのみなので、二重コロンまたは匿名関数を使用して関数を実装しますただし、これら 2 つのメソッドのコードは比較的煩雑です。コード量を簡略化し、コードを簡潔明瞭にするために Lambda 式を導入したため、Lambda 式の本質は実際には関数型オブジェクトです。本当の魅力は、メソッドが動的に設定されることです。
例: パラメーターの型が関数型であるメソッド a が存在します。
fun a(fb : (Int , String) -> String) {
}
メソッド a を呼び出すには、関数型のオブジェクトを渡す必要があります。
通常、次の 2 つのメソッドがあります。
- 二重コロンを使用できます。
fun b(p1 : Int , p2 : String) : String {
return p2 + p1
}
a(::b)
- 匿名関数を使用する
val b : (Int , String) -> String = fun(p1 : Int , p2 : String) : String {
return p2 + p1
}
a(b)
もちろん、匿名関数を直接渡すこともできます。
a(fun(p1 : Int , p2 : String) : String {
return p2 + p1
})
無名関数を使用する方法は非常に煩雑であることがわかりますが、次にそれを簡素化するために Lambda 式を導入します。
1.) ラムダ式の形式は次のとおりです:
{パラメータ 1: パラメータのタイプ、パラメータ 2: パラメータのタイプ、... -> 実行コード ブロック}
注: 実行コード ブロックの式の最後の行は戻り値です。 Lambda 式の
. この式 戻り値の型は、宣言された戻り値の型と一致している必要があります。
したがって、ラムダ式を使用して、上記の無名関数を次のように表現できます。
a({
p1 : Int , p2 : String ->
p2 + p1
})
2.) ラムダの関数型を明示的に宣言した場合、ラムダ パラメーター リスト内のパラメーターの型を省略できるため、次のように
簡略化できます。
a({
p1 , p2 ->
p2 + p1
})
3.) ラムダ式が関数呼び出しの最後の実際のパラメータとして使用される場合、ラムダ式を括弧の外側に配置できるため、次のよう
に簡略化できます。
a() {
p1 , p2 ->
p2 + p1
}
4.) ラムダが関数の唯一の実パラメータである場合、関数の空のかっこも削除できるため、次の
ように簡略化できます。
a {
p1 , p2 ->
p2 + p1
}
継続的な簡素化を経て、これが私たちの日常生活で最も一般的な形式になりました。
5.) ラムダ式にパラメータが 1 つだけあり、このパラメータの型が推定できる場合、このパラメータを置き換えるためにデフォルトのパラメータ名が生成されます。このとき、名前を明示的に宣言する必要はありません。これは、パラメータを省略できることを意味します。
例は次のとおりです。
fun a(fb : (Int ) -> String) {
}
a{
it.toString()
}
注: 複数のラムダがネストされている場合、各ラムダ式のパラメータを明示的に宣言することが最善です。そうしないと、それがどの値を参照しているかを把握することが困難になり、コードの可読性に重大な影響を及ぼします。
6.)ラムダ式を使用する場合、アンダースコア (_) を使用して実行コード ブロック内の未使用のパラメーターを示し、このパラメーターが処理されないことを示すことができます。
a {
_ , p2 ->
p2
}
2.SAM変換
前回の記事では、インターフェイスを使用して Java で関数を転送する方法についても説明しましたが、Kotlin では、SAM 変換であるインターフェイスのラムダ構文も提供しています。
-
SAM 変換はインターフェイスでのみ機能し、抽象クラスでは機能しません。これらの抽象クラスであっても、抽象メソッドは 1 つしかありません。
-
これは関数型インターフェイス、つまり fun インターフェイスを使用して宣言されたインターフェイスである必要があります。このインターフェイスは抽象メソッドを 1 つだけ持つことができます(明らかに、ラムダ式の最終目標は動的関数を持つことです)。SAM
変換はラムダを関数に変換することです。インターフェースインスタンスから生成された関数 -
関数インターフェイスと関数タイプは同じものではありません。これは簡単に理解できます。一方はインターフェイスで、もう一方はデータ型です。これらを混合することはできません。
例は次のとおりです。 関数インターフェイスを定義します。
fun interface Click {
fun click(a : Int) : String
}
fun a(c : Click) {
c.click(1)
}
便宜上、ラムダを使用せずに、通常はオブジェクト式を使用して匿名内部クラスのオブジェクトを構築し、それを渡します。
a(object : Click {
override fun click(a : Int) : String {
return a.toString()
}
})
ラムダを使用すると、構文は上記のものと変わりません。
a {
a -> a.toString() }