Kotlin - 内联参数回调的非法使用
Kotlin - Illegal usage of inline parameter callback
我正在将 function
的 lambda
转换为 parameter
为 inline function
以提高性能。
我有 MutableList<(Authenticate) -> Unit>
类型 lambda
的 list
变量作为 class 中的数据成员。当我尝试将 lambda parameter
添加到 list
.
Kotlin 编译器说:
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()
)))
}
}
})
}
}
}
Inlining inserts the code in the lambda directly into the call site,这消除了拥有函数对象的开销。
例如,这大致导致 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
修饰符,因为性能优势将很小。
编译器应该识别这个:
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.
使用 lambdas 和 reified
generic type parameters 时,内联方法的主要原因是性能 。从 Kotlin 1.1 开始,也可以为没有支持字段的属性提供内联 属性 访问器。
简而言之,如果你没有lambda参数(或者没有reified
类型参数,在这种情况下你必须),标记一个函数通常是没有意义的作为 inline
.
我正在将 function
的 lambda
转换为 parameter
为 inline function
以提高性能。
我有 MutableList<(Authenticate) -> Unit>
类型 lambda
的 list
变量作为 class 中的数据成员。当我尝试将 lambda parameter
添加到 list
.
Kotlin 编译器说:
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()
)))
}
}
})
}
}
}
Inlining inserts the code in the lambda directly into the call site,这消除了拥有函数对象的开销。
例如,这大致导致 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
修饰符,因为性能优势将很小。
编译器应该识别这个:
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.
使用 lambdas 和 reified
generic type parameters 时,内联方法的主要原因是性能 。从 Kotlin 1.1 开始,也可以为没有支持字段的属性提供内联 属性 访问器。
简而言之,如果你没有lambda参数(或者没有reified
类型参数,在这种情况下你必须),标记一个函数通常是没有意义的作为 inline
.