Kotlinの noinline
と crossinline
がどういうときに必要になるかを調べました。
noinline
noinline
は inline
関数に2つ関数を渡してる場合などで、片方が inline
として扱えない関数につけるものになります。
inline fun f(block1: () -> Unit, noinline block2: () -> Unit) {
}
使い方は分かるのですが、まず、そもそも inline
関数として扱えないものにどういうのがあるかについて調べました。
inline関数として扱えないものは、受け取った関数を inline
関数ではない関数に渡すときです。
// inline関数
inline fun f(block: () -> Unit) {
f2(block) // compile error
}// not inline関数
fun f2(block: () -> Unit) {
block()
}
上の例では inline
関数(f)から inline
ではない関数(f2)に引数の関数を渡しています。このときコンパイルエラーになるため inline
関数にすることができません。
もう1つのパターンとして、インスタンスメソッドも同様です。
class Sample {
fun run(block: () -> Unit) {
block()
}
}inline fun f(block: () -> Unit) {
val sample = Sample()
sample.run(block) // compile error
}
これを解決するには、2つ方法があります。
まずは単純に inline
を外してしまう方法です。
// not inline関数
fun f(block: () -> Unit) {
f2(block) // ok
}// not inline関数
fun f2(block: () -> Unit) {
block()
}
もう一つが呼び出し先も inline
関数にする
// inline関数
inline fun f(block: () -> Unit) {
f2(block) // ok
}// inline関数
inline fun f2(block: () -> Unit) {
block()
}
上記を踏まえて、 noinline
が必要になるパターンとしては以下のような感じです。
// inline関数
inline fun f(block1: () -> Unit, noinline block2: () -> Unit) {
block1()
f2(block2)
}// not inline関数
fun f2(block: () -> Unit) {
block()
}
上の例で block1 は inline
で処理できるが、block2 のほうは inline
ではない関数を呼んでるので noinline
をつけて対応する感じになります。
crossinline
こちらも inline
関数を使用する際に必要になる場合があります。使いかたは引数の関数に crossinline
をつけるだけです。
inline fun f(crossinline block: () -> Unit) {
}
crossinline
についても必要な状況がどういうときかを調べました。
こちらも inline
関数から inline
ではない関数を呼び出すときに必要になる場合があります。
// inline関数
inline fun f(block: () -> Unit) {
f2 {
block() // compile error
}
}// not inline関数
fun f2(block: () -> Unit) {
block()
}
先程、 inline
のほうとは違って、関数を渡すのではなく、lambda式から受け取った関数を実行しています。
また、以下のような状況も同様です。
// inline関数
inline fun f(block: () -> Unit) {
Executors.newSingleThreadExecutor().execute {
block() // compile error
}
}
これを crossinline
を使うことで解決することができます。
// inline関数
inline fun f(crossinline block: () -> Unit) {
f2 {
block() // ok
}
}// not inline関数
fun f2(block: () -> Unit) {
block()
}
別の方法としては、 呼び出し元も呼び出しも両方とも inline
にするか、逆に inline
を外すかということもできます。