我正在将function
lambda
parameter
inline function
转换为list
以提升效果。
我有lambda
MutableList<(Authenticate) -> Unit>
类型lambda parameter
变量作为类中的数据成员。当我尝试将list
添加到// 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()
)))
}
}
})
}
}
}
。
Kotlin编译器说:
非法使用内联参数回调
这是代码
<ul id="cart-sidebar" class="mini-products-list" ng-init="cartArray.total = {}">
<li class="item odd" ng-if="cartArray.length === 0">No items in your cart..</li>
<li class="item odd" ng-repeat='y in cartArray'>
<a href="shopping_cart.html" class="product-image"><img ng-src="" alt="" width="65"></a>
<div class="product-details">
<a href="#" title="Remove This Item" class="remove-cart" ng-click="removeFromCart(y)"><i class="pe-7s-trash"></i></a>
<p class="product-name"><a href="shopping_cart.html">{{y.prodName}}</a> </p>
<strong>1</strong> x <span class="price" ng-init='cartArray.total.prodAmt = cartArray.total.prodAmt + y.prodAmt'>Rs. {{y.prodAmt}}</span>
</div>
</li>
</ul>
<div ng-if="cartArray.length > 0" class="top-subtotal">Subtotal: <span class="price">{{cartArray.total.prodAmt }}</span></div>
答案 0 :(得分:8)
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
修饰符,因为性能优势最小。
编译器应该认识到这一点:
请注意,如果内联函数没有inlinable函数参数且没有reified类型参数,编译器将发出警告,因为内联这些函数不太可能有用。
内联方法的主要原因是使用lambdas 和reified
generic type parameters时的性能。从Kotlin 1.1开始,也可以为没有后备字段的属性提供内联属性访问器。
简而言之,如果您没有lambda参数(或没有reified
类型参数,在这种情况下必须),将函数标记为{{1}通常没有意义}。