高次関数は非常に役立ち、reusability
コードを本当に改善できます。ただし、それらの使用に関する最大の懸念の1つは効率です。ラムダ式はクラス(多くの場合匿名クラス)にコンパイルされ、Javaでのオブジェクト作成は負荷の高い操作です。関数をインライン化することで、すべての利点を維持しながら、高次関数を効果的に使用できます。
ここにインライン関数があります
関数がとしてマークされている場合、inline
コードのコンパイル中に、コンパイラーはすべての関数呼び出しを関数の実際の本体で置き換えます。また、引数として提供されたラムダ式は、実際の本体に置き換えられます。それらは関数としてではなく、実際のコードとして扱われます。
つまり、-インライン->呼び出されるのではなく、コンパイル時に関数の本体コードに置き換えられます...
Kotlinでは、関数を別の関数(いわゆる高階関数)のパラメーターとして使用する方が、Javaより自然に感じられます。
ただし、ラムダの使用にはいくつかの欠点があります。それらは匿名クラス(したがってオブジェクト)であるため、メモリが必要です(アプリの全体的なメソッド数が増えることもあります)。これを回避するために、メソッドをインライン化できます。
fun notInlined(getString: () -> String?) = println(getString())
inline fun inlined(getString: () -> String?) = println(getString())
上記の例から:-これら2つの関数はまったく同じことを行います-getString関数の結果を出力します。1つはインライン化され、もう1つはインライン化されません。
逆コンパイルされたJavaコードを確認すると、メソッドが完全に同一であることがわかります。これは、inlineキーワードがコードを呼び出しサイトにコピーするようコンパイラーに指示するためです。
ただし、以下のように関数タイプを別の関数に渡す場合:
//Compile time error… Illegal usage of inline function type ftOne...
inline fun Int.doSomething(y: Int, ftOne: Int.(Int) -> Int, ftTwo: (Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/
}
これを解決するには、関数を次のように書き換えます。
inline fun Int.doSomething(y: Int, noinline ftOne: Int.(Int) -> Int, ftTwo: (Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/}
以下のような高次関数があるとします。
inline fun Int.doSomething(y: Int, noinline ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/}
ここで、ラムダパラメーターが1つだけあり、それを別の関数に渡す場合、コンパイラーはinlineキーワードを使用しないように指示します。したがって、上記の関数を次のように書き換えることができます。
fun Int.doSomething(y: Int, ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/
}
注:-キーワードnoinlineも削除する必要がありました。インライン関数にのみ使用できるためです。
このような関数があるとしましょう ->
fun intercept() {
// ...
val start = SystemClock.elapsedRealtime()
val result = doSomethingWeWantToMeasure()
val duration = SystemClock.elapsedRealtime() - start
log(duration)
// ...}
これは問題なく機能しますが、関数のロジックの大部分が測定コードで汚染されているため、同僚が現在の作業を行うのが難しくなっています。:)
インライン関数がこのコードにどのように役立つかを次に示します。
fun intercept() {
// ...
val result = measure { doSomethingWeWantToMeasure() }
// ...
}
inline fun <T> measure(action: () -> T) {
val start = SystemClock.elapsedRealtime()
val result = action()
val duration = SystemClock.elapsedRealtime() - start
log(duration)
return result
}
これで、測定コードの行をスキップすることなく、intercept()関数の主な目的を読み取ることに集中できます。また、他の場所でそのコードを再利用するオプションも利用できます。
インラインでは、measure(myLamda)のようにラムダを渡すのではなく、クロージャー({...})内でラムダ引数を使用して関数を呼び出すことができます。