我正在编写一个Kotlin 内联类,以使Decimal4J更方便,而无需实例化任何对象。我担心范围函数可能会创建lambda对象,从而使整个事情变得毫无意义。
考虑下面示例中的函数compareTo。
/* imports and whatnot */
@JvmInline
value class Quantity(val basis: Long) {
companion object {
val scale: Int = 12
val metrics: ScaleMetrics = Scales.getScaleMetrics(scale)
val arithmetic: DecimalArithmetic = metrics.defaultArithmetic
}
operator fun compareTo(alt: Number): Int {
with(arithmetic) {
val normal = when (alt) {
is Double -> fromDouble(alt)
is Float -> fromFloat(alt)
is Long -> fromLong(alt)
is BigDecimal -> fromBigDecimal(alt)
is BigInteger -> fromBigInteger(alt)
else -> fromLong(alt.toLong())
}
return compare(basis, normal)
}
}
}with(arithmetic)作用域是否在堆中创建lambda?kotlinlang.org上的文档始终将作用域代码称为lambda表达式。有没有办法不用创建对象来使用作用域函数?
发布于 2022-08-06 01:22:24
所有内置的作用域函数(包括with )都被标记为inline,这意味着实现直接植入到调用它的代码中。一旦发生这种情况,就可以对lambda调用进行优化。
更具体的说,这里是实施 of with (去掉了Kotlin契约的内容,因为这里不相关)。
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
return receiver.block()
}扩展方法在编译时解析语法糖,并且一直是这样,所以这是有效的。
public inline fun <T, R> with(receiver: T, block: (T) -> R): R {
return block(receiver) // (with `this` renamed by the compiler)
}所以当我们打电话
operator fun compareTo(alt: Number): Int {
with (arithmetic) {
println("Hi :)")
println(foobar()) // Assuming foobar is a method on arithmetic
}
}inline将把它转换成
operator fun compareTo(alt: Number): Int {
({
println("Hi :)")
println(it.foobar()) // Assuming foobar is a method on arithmetic
})(arithmetic)
}任何值其盐分的优化器都可以看到,这是一个被立即评估的函数,所以我们现在应该继续这样做。我们最后的结果是
operator fun compareTo(alt: Number): Int {
println("Hi :)")
println(arithmetic.foobar()) // Assuming foobar is a method on arithmetic
}这就是你一开始就会写的。
所以,tl;dr,编译器是足够聪明的,能够解决它。你不用担心。这是在高级语言中工作的好处之一。
顺便说一下,这不仅仅是抽象的。我只是在我自己的机器上编译了上面的代码,然后对JVM字节码进行反编译,看看它到底做了什么。这有点麻烦(因为JVM必然会有很多噪音),但是没有分配lambda对象,函数只是直接调用println两次。
如果您感兴趣,Kotlin以这个示例函数为例
fun compareTo(alt: Number): Unit {
return with(arithmetic) {
println("Hi :)")
println(foobar())
}
}对这个Java来说,在被解压缩之后,
public static final void compareTo-impl(long arg0, @NotNull Number alt) {
Intrinsics.checkNotNullParameter((Object)alt, (String)"alt");
long l = arithmetic;
boolean bl = false;
boolean bl2 = false;
long $this$compareTo_impl_u24lambda_u2d0 = l;
boolean bl3 = false;
String string = "Hi :)";
boolean bl4 = false;
System.out.println((Object)string);
int n = so_quant.foobar-impl($this$compareTo_impl_u24lambda_u2d0);
bl4 = false;
System.out.println(n);
}虽然有点吵闹,但想法完全一样。所有这些毫无意义的局部变量都将由一个好的JIT发动机来处理。
https://stackoverflow.com/questions/73256480
复制相似问题