我正在寻找好的做法,以避免一遍又一遍地重写相同的代码以实现拆箱。说我有这样的事情:

def speedyArrayMaker[@specialized(Long) A: ClassTag](...): Array[A] = {
  val builder = Array.newBuilder[A]
  // do stuff with builder
  builder.result
}


这将在可能的情况下在builder的基础上产生未装箱的存储,但据我了解,由于我正在经历非专业化的ArrayBuilder特性,因此没有未装箱的方法调用。

在专门针对Long的单态世界中,我会编写val builder = new ArrayBuilder.ofLong()并完全避免装箱,但由于没有告诉ArrayBuilder / Builder专门针对所有原始类型,所以我想不到避免重复工作的方法。我想到的一种方法可能是在speedyArrayMaker中:

val (add, builder): (A => Unit, ArrayBuilder[A]) = implicitly[ClassTag[A]].runtimeClass match {
  case java.lang.Long.TYPE =>
    val builder = new ArrayBuilder.ofLong()
    ((x: Long) => builder += x, builder).asInstanceOf
  case _ =>
    val builder = Array.newBuilder[A]
    ((x: A) => builder += x, builder)
}


由于这只是+=方法,我们真的很想得到专门化,然后我们得到Function1add,它专门针对Long。用javap检查,确实可以

90:  invokestatic    #118; //Method scala/runtime/BoxesRunTime.boxToLong:(J)Ljava/lang/Long;
93:  invokeinterface #127,  2; //InterfaceMethod scala/collection/mutable/Builder.$plus$eq:(Ljava/lang/Object;)Lscala/collection/mutable/Builder;


Array.newBuilder[A]版本(甚至在专用输出中),并且:

252: invokeinterface #204,  3; //InterfaceMethod scala/Function1.apply$mcVJ$sp:(J)V


对于卷积版本。我可以将此模式组合为“专业化的构建器帮助程序”功能,但是当它仍在运行时基于专业化时在编译时已知的某些东西进行分派时,感觉很难看。最终,我想说的是,我的建议是背负Function1已经专门化的事实,我并不特别喜欢它。

我可以使用一些巧妙的技巧使它变得更愉快吗?我意识到这是一个非常低级的细节,很少会影响性能,但是考虑到所有ArrayBuilder.of*专门类中的工作量/代码重复量,似乎很遗憾放弃了它们的一些优点。交换为多态的。

编辑
我想到了一件丑陋的事情,但我希望能起作用:

def builderOf(x: Array[Int]): ArrayBuilder.ofInt = new ArrayBuilder.ofInt()
def builderOf(x: Array[Long]): ArrayBuilder.ofLong = new ArrayBuilder.ofLong()
def builderOf[A: ClassTag](x: Array[A]): ArrayBuilder[A] = ArrayBuilder.make[A]


然后在我的专门功能内:

val witness: Array[A] = null
val builder = builderOf(witness)


但是即使在专用版本中,它似乎也可以调用通用builderOf(即使有足够的类型信息可以调用Array[Long]版本)。有人知道为什么这行不通吗?与我提出的另一种方法相比,该方法似乎很干净。我想我希望有一种更“宏似”的专业化方法,但是我想不能保证它对于所有实例化都是正确的,除非它为每个专业化选择相同的方法。

最佳答案

您可以按照以下方式尝试((野蛮的名字),

import scala.collection.mutable.ArrayBuilder
import scala.reflect.ClassTag

trait SpecializedArrayBuilder[@specialized(Long) A] {
  def +=(a: A)
  def result: Array[A]
}

trait LowPrioritySpecializedArrayBuilder {
  implicit def defaultBuilder[A: ClassTag] = new SpecializedArrayBuilder[A] {
    val builder = ArrayBuilder.make[A]
    def +=(a: A) = builder += a
    def result = builder.result
  }
}

object SpecializedArrayBuilder extends LowPrioritySpecializedArrayBuilder {
  implicit val longBuilder = new SpecializedArrayBuilder[Long] {
    val builder = new ArrayBuilder.ofLong
    def +=(a: Long) = builder += a
    def result = builder.result
  }
}

object Specialized {
  def speedyArrayMaker[@specialized(Long) A](a: A)
    (implicit builder: SpecializedArrayBuilder[A]): Array[A] = {
    builder += a
    builder.result
  }

  def main(arg: Array[String]) {
    val arr = speedyArrayMaker(1L)
    println(arr)
  }
}

07-24 15:52