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

Kas*_*ala 0 lambda android inline kotlin

我将我的functionlambda作为parameterinline function性能改进.

listlambda类型的MutableList<(Authenticate) -> Unit>变量作为类数据成员.当我尝试添加lambda parameterlist.

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()
                                )))
                            }
                }
            })
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Moi*_*ira 8

内联将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") }
}
Run Code Online (Sandbox Code Playgroud)

被转换为:

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

如果你有

pendingAuthenticateCallbacks += callback
Run Code Online (Sandbox Code Playgroud)

这是不可能的,因为callback必须是一个对象才能将它添加到列表中.

您需要添加noinline修饰符.

粗略的近似是指内联lambda不能被视为一个对象,因为它并不真正作为一个对象存在.它直接使用而不是作为对象创建.

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

pendingAuthenticateCallbacks += { callback() } // Not a good idea
Run Code Online (Sandbox Code Playgroud)

但这完全打败了内联点(不要这样做!).

但是,创建参数noinline意味着您的方法现在具有可以内联的零lambda参数,因此您也可以删除inline修饰符,因为性能优势最小.

编译器应该认识到这一点:

请注意,如果内联函数没有可嵌入的函数参数且没有具体的类型参数,编译器将发出警告,因为内联此类函数不太可能有益.


内联方法的主要原因是使用lambdareified泛型类型参数时的性能.作为科特林1.1的,但也可以具有用于属性内嵌属性访问而不支持字段.


简而言之,如果您没有lambda参数(或者没有reified类型参数,在这种情况下您必须),将函数标记为无意义通常是没有意义的inline.