加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Boilerplate-free Scala ArrayBuilder专业化

发布时间:2020-12-16 18:38:18 所属栏目:安全 来源:网络整理
导读:我正在寻找良好的做法,以避免一遍又一遍地重写相同的代码,以实现unboxedness.说我有这样的事情: def speedyArrayMaker[@specialized(Long) A: ClassTag](...): Array[A] = { val builder = Array.newBuilder[A] // do stuff with builder builder.result}
我正在寻找良好的做法,以避免一遍又一遍地重写相同的代码,以实现unboxedness.说我有这样的事情:

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

这将导致我的构建器在可能的情况下存在未装箱的存储,但据我所知,没有未装箱的方法调用它,因为我正在经历非专用的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)
}

因为它只是=方法我们真正关心专业化,然后我们得到一个专门用于Long的Function1.用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

对于复杂的版本.我可以将这个模式打包成一个“专门的构建器助手”函数,但是它感觉很难看,特别是当它仍然在运行时根据在特化期间编译时已知的事情进行调度时.最后我要说我的建议是捎带Power1已经专门化的事实,我并不特别喜欢它.

有没有巧妙的技巧可以让它变得更加愉快?我意识到这是一个非常低级的细节,并且很少会对性能至关重要,但考虑到所有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)
  }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读