Scala中惯用语的高效标量映射/映射?
从另一个表达式的深处多次访问标量表达式的最简洁和字节码效率最高的方法是什么 以下代码(exc.scalar4)中的所有函数都可以按需要运行。但是只有字节码器发出有效的字节码(尽管以ISTORE 2 ILOAD 2结尾很糟糕),其他的每一个都会产生六个调用 此习惯用法还可以方便地将元组的任意部分作为参数传递:Scala中惯用语的高效标量映射/映射?,scala,bytecode,Scala,Bytecode,从另一个表达式的深处多次访问标量表达式的最简洁和字节码效率最高的方法是什么 以下代码(exc.scalar4)中的所有函数都可以按需要运行。但是只有字节码器发出有效的字节码(尽管以ISTORE 2 ILOAD 2结尾很糟糕),其他的每一个都会产生六个调用 此习惯用法还可以方便地将元组的任意部分作为参数传递: for (a_tuple) { f(_._3, _._1) + g(_._2) } // caution NOT legal Scala 在本例中,intro表示一个只应调用一次的昂贵函
for (a_tuple) { f(_._3, _._1) + g(_._2) } // caution NOT legal Scala
在本例中,intro表示一个只应调用一次的昂贵函数
object Hack extends App
{
@inline final def fur[T, V](x :T)(f :T => V) :V = f(x)
@inline final def pfor[T, V](x :T)(pf :PartialFunction[T, V]) = pf(x)
@inline final def cfor[T, V](x :T)(f :T => V) :V = x match { case x => f(x) }
def intro :Int = 600 // only one chance to make a first impression
def bytecoder = intro match { case __ => __ + __ / 600 }
def functional = fur(intro) (x => x + x / 600)
def partial = pfor(intro) { case __ => __ + __ / 600 }
def cased = cfor(intro) ($ => $ + $ / 600)
def optional = Some(intro).map(? => ? + ? / 600).get
def folder = Some(intro).fold(0)(? => ? + ? / 600)
// the for I wish for
def scalar4 = for(intro) (_ + _ / 600) // single underline!
println(bytecoder, functional, partial, cased, optional, folder)
}
公共字节码器()I
只需创建一个带有临时值的本地块即可。它很紧凑:只比“惯用”管道长一个字符 它是高效的:尽可能减少字节码
// def localval = { val x = whatever; x * x / 600 }
public int localval();
Code:
0: aload_0
1: invokevirtual #18; //Method whatever:()I
4: istore_1
5: iload_1
6: iload_1
7: imul
8: sipush 600
11: idiv
12: ireturn
它唯一没有做的就是充当后缀操作符,当您确实需要该表单并且不能容忍额外的字节码时,您可以使用match
// Canadian scalar "for" expression
@inline final case class four[T](x: T)
{
@inline def apply(): T = x
@inline def apply[V](f: Function1[T, V]): V = f(x)
@inline def apply[V](f: Function2[T, T, V]): V = { val $ = x; f($, $) }
@inline def apply[V](f: Function3[T, T, T, V]): V = { val $ = x; f($, $, $) }
@inline def apply[V](f: Function4[T, T, T, T, V]): V = { val $ = x; f($, $, $, $) }
// ...
}
// Usage
val x = System.currentTimeMillis.toInt % 1 + 600
def a = four(x)() + 1
def b = four(x)(_ + 1)
def c = four(x)(_ + _ / x)
def d = four(x)(_ + _ / _)
def e = four(x)(_ + _ / _ - _) + 600
println(a, b, c, d, e)
有了这个four(){}
,字节码和性能被牺牲,取而代之的是风格
此外,这也危险地打破了传统,即每个参数只使用一次下划线。
def tempvar={var x=intro;x+x/600}
?你可以把块放在任何地方,你知道。如果你想在Scala中寻找“字节码效率”,那你就找错地方了。JIT难道不能优化最终无用的ISTORE 2/ILOAD 2吗?@BrunoReis-当然可以,但由于这是一个如此简单的优化,我很惊讶scalac没有这样做。接受它是因为它的字节码效率高且简单。但是我仍然不喜欢分号,并且不得不给匿名的val
命名。谢谢你对这个问题的关注。
// def localval = { val x = whatever; x * x / 600 }
public int localval();
Code:
0: aload_0
1: invokevirtual #18; //Method whatever:()I
4: istore_1
5: iload_1
6: iload_1
7: imul
8: sipush 600
11: idiv
12: ireturn
// Canadian scalar "for" expression
@inline final case class four[T](x: T)
{
@inline def apply(): T = x
@inline def apply[V](f: Function1[T, V]): V = f(x)
@inline def apply[V](f: Function2[T, T, V]): V = { val $ = x; f($, $) }
@inline def apply[V](f: Function3[T, T, T, V]): V = { val $ = x; f($, $, $) }
@inline def apply[V](f: Function4[T, T, T, T, V]): V = { val $ = x; f($, $, $, $) }
// ...
}
// Usage
val x = System.currentTimeMillis.toInt % 1 + 600
def a = four(x)() + 1
def b = four(x)(_ + 1)
def c = four(x)(_ + _ / x)
def d = four(x)(_ + _ / _)
def e = four(x)(_ + _ / _ - _) + 600
println(a, b, c, d, e)