1. ホーム
  2. kotlin

Kotlinのcrossinlineとnoinlineの違いは何ですか?

2023-08-20 01:56:21

質問

  1. このコード は警告を伴ってコンパイルされます。 ( パフォーマンスへの影響は軽微 ):

    inline fun test(noinline f: () -> Unit) {
        thread(block = f)
    }
    
    
  2. このコード はコンパイルされません。 ( インラインパラメータの不正な使用 ):

    inline fun test(crossinline f: () -> Unit) {
        thread(block = f)
    }
    
    
  3. このコード は警告を伴ってコンパイルされます。 ( パフォーマンスへの影響は軽微 ):

    inline fun test(noinline f: () -> Unit) {
        thread { f() }
    }
    
    
  4. このコード は警告もエラーもなくコンパイルされます。 :

    inline fun test(crossinline f: () -> Unit) {
        thread { f() }
    }
    
    

以下は私の質問です。

  • なぜ(2)はコンパイルできず、(4)はコンパイルできるのでしょうか?
  • とはいったい何が違うのでしょうか? noinlinecrossinline ?
  • (3)で性能向上がないのであれば、(4)はなぜそうなるのでしょうか?

どのように解決するのですか?

からの インライン関数リファレンス :

インライン関数の中には、関数本体から直接ではなく、ローカルオブジェクトやネストされた関数などの別の実行コンテキストから、パラメータとして渡されたラムダを呼び出すものがあることに注意してください。このような場合、ローカルでない制御フローもラムダでは許されない。このことを示すために、ラムダパラメータには crossinline 修飾子を付ける必要があります。

したがって、例2.はコンパイルできません。 crossinline はローカルな制御フローのみを強制し、式 block = f はそれに違反します。例 1 はコンパイルできます。 noinline はそのような動作を必要としないからです (明らかに、それは普通の関数パラメータなので)。

例1と3では、ラムダパラメータが noinline と表示され inline コンパイラは何かをインライン化したいのですが、インライン化できそうなものはすべてインライン化しないようにマークされています。

2つの関数を考えてみましょう。 A B

A

inline fun test(noinline f: () -> Unit) {
    thread { f() }
}

B

fun test(f: () -> Unit) {
    thread { f() }
}

機能 A は関数 B のように振る舞います。 f はインライン化されません( B の本文はインライン化されません。 test であるのに対し A 関数では、ボディに thread { f() } はまだインライン化されます)。

さて、これは例4には当てはまりません。 crossinline f: () -> Unit パラメータ はインライン化できますが、前述の非ローカル制御フロールール(グローバル変数に新しい値を代入するような)に違反できないだけです。また、インライン化できる場合、コンパイラはパフォーマンスの向上を想定しており、例3のような警告は出しません。