Kotlin-非法使用内联参数回调



我正在将lambda作为parameterfunction转换为inline function,以改进性能。

我将MutableList<(Authenticate) -> Unit>类型的lambdalist作为类中的数据成员。当我尝试将lambda parameter添加到list中时。

Kotlin编译器说:

非法使用内联参数回调

这是代码

// Some code skipped
object Odoo {
    val pendingAuthenticateCallbacks = mutableListOf<(Authenticate) -> Unit>()
    inline fun authenticate(
        login: String, password: String, database: String,
        quick: Boolean = false, crossinline callback: Authenticate.() -> Unit
    ) {
        // Following statement has error saying
        // Illegal usage of inline parameter callback. add 'noinline' modifier to parameter declaration.
        pendingAuthenticateCallbacks += callback
        // Error in above statement
        if (pendingAuthenticateCallbacks.size == 1) {
            // Retrofit2 Object boxing code skipped
            val call = request.authenticate(requestBody)
            call.enqueue(object : Callback<Authenticate> {
                override fun onFailure(call: Call<Authenticate>, t: Throwable) {
                    (pendingAuthenticateCallbacks.size - 1 downTo 0)
                            .map { pendingAuthenticateCallbacks.removeAt(it) }
                            .forEach {
                                it(Authenticate(httpError = HttpError(
                                        Int.MAX_VALUE,
                                        t.message!!
                                )))
                            }
                }
                override fun onResponse(call: Call<Authenticate>, response: Response<Authenticate>) {
                    (pendingAuthenticateCallbacks.size - 1 downTo 0)
                            .map { pendingAuthenticateCallbacks.removeAt(it) }
                            .forEach {
                                it(Authenticate(httpError = HttpError(
                                        response.code(),
                                        response.errorBody()!!.string()
                                )))
                            }
                }
            })
        }
    }
}

inlinging在lambda 中插入代码直接 中插入呼叫站点,该网站删除了具有函数对象的开销。

例如,这大致在main中大致在这里:

fun withLambda(lambda: () -> Unit) {
    lambda()
}
inline fun inlinedLambda(lambda: () -> Unit) {
    lambda()
}
fun main(args: Array<String>) {
    withLambda { println("Hello, world") }
    inlinedLambda { println("Hello, world") }
}

被转换为此:

fun main(args: Array<String>) {
    withLambda { println("Hello, world") }
    println("Hello, world") // <- Directly inserted!
}

如果您有

pendingAuthenticateCallbacks += callback

这是不可能的,因为callback必须是将其添加到列表中的对象。

您需要添加noinline修饰符。

粗略的近似值是要说一个嵌入的lambda不能被视为对象,因为并不是真正存在作为对象。它直接使用而不是被创建为对象。

当然,您可以创建一个包含的lambda:

pendingAuthenticateCallbacks += { callback() } // Not a good idea

,但这将完全击败内在的观点(不要这样做!)。

但是,制作参数 noinline意味着您的方法现在具有零lambda参数,可以夹住,因此您不妨删除 inline修改器,因为性能益处将是最小的。

编译器应认识到这一点:

请注意,如果Inline函数没有不可限制的函数参数,并且没有Reified类型参数,则编译器将发出警告,因为对此类函数的内衬不太可能是有益的。


使用lambdas 和reified通用类型参数时,插入方法的主要原因是用于性能。从Kotlin 1.1开始,也可以具有无背后属性的属性属性登录器。


简而言之,如果您没有lambda参数(或没有reified键入参数,在这种情况下,您必须必须),将功能标记为inline

最新更新