Kotlin-非法使用内联参数回调 [英] Kotlin - Illegal usage of inline parameter callback

查看:90
本文介绍了Kotlin-非法使用内联参数回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将具有lambda作为parameterfunction转换为inline function,以提高性能.

I'm converting my function having lambda as parameter into inline function for performance improvement.

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

I have list of lambda of type MutableList<(Authenticate) -> Unit> variable as data member in class. When I try to adding lambda parameter into the list.

Kotlin编译器说:

Kotlin compiler says:

非法使用内联参数回调

Illegal usage of inline parameter callback

这是代码

// 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()
                                )))
                            }
                }
            })
        }
    }
}

推荐答案

内联插入代码在lambda中直接 进入调用站点,这消除了拥有函数对象的开销.

Inlining inserts the code in the lambda directly into the call site, which removes the overhead of having a function object.

例如,这大致导致main出现在这里:

For example, this roughly results in main here:

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必须是一个对象才能将其添加到列表中.

This is impossible because callback must be an object in order for it to be added to the list.

您需要添加noinline修饰符.

一个粗略的近似值是说,内联的lambda不能被视为一个对象,因为它实际上并不存在.作为一个对象.直接使用而不是将其创建为对象.

A rough approximation would be to say that an inlined lambda cannot be treated as an object, as it doesn't really exist as an object. It is used directly instead of being created as an object.

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

Of course, you could create a containing lambda:

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

但是这将完全击败内联的观点(不要这样做!).

but this would entirely defeat the point of inlining (don't do this!).

但是,将参数设置为noinline意味着您的方法现在可以内联零个lambda参数,因此您最好删除inline修饰符,因为这样做对性能的影响很小.

However, making the parameter noinline would mean your method now has zero lambda parameters that can be inlined, so you might as well just remove the inline modifier as performance benefit would be minimal.

编译器应认识到这一点:

The compiler should recognize this:

请注意,如果内联函数没有不可插入的函数参数且没有经过修饰的类型参数,则编译器将发出警告,因为内联此类函数不太可能是有益的.

Note that if an inline function has no inlinable function parameters and no reified type parameters, the compiler will issue a warning, since inlining such functions is very unlikely to be beneficial.


内联方法的主要原因是使用lambda时的性能


The main reason for inlining methods is for performance when using lambdas and for reified generic type parameters. As of Kotlin 1.1, it is also possible to have an inline property accessor for properties without a backing field.

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

In short, if you have no lambda parameters (or no reified type parameters, in which case you must), it is usually pointless to mark a function as inline.

这篇关于Kotlin-非法使用内联参数回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆