我正在尋找良好的做法,以避免一遍又一遍地重寫相同的代碼來實現拆箱。說我有這樣的事情:無鍋板Scala ArrayBuilder專業化
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)
}
因爲它是唯一我們真正關心獲取專業的+=
方法,然後我們得到了add
這是專門在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
了令人費解的版本。我可以把這個模式放到「專門的構建器幫助器」函數中,但是它會感覺很難看,特別是當它在運行時仍然根據專業化期間編譯時已知的事情進行調度時。最終我會說我的建議是搭配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]
版本)。任何人都知道爲什麼這不起作用?與我提議的另一個相比,這種方法看起來相當乾淨。我想我希望能有一種更類似於宏觀的專業化方法,但我想不能保證它對於所有的實例都是類型正確的,除非它爲每個專業化選擇相同的方法:(
我不知道看到什麼,你會做如何才能讓你的任何專業,因爲'ArrayBuidler'沒有專用的(因此' + ='即使從專門的方法中調用也不會被專門化)。如果完全繞過ArrayBuidler,您將只獲得專業化(例如通過定義您自己的專用版本)。 – 2013-04-30 21:01:17
實際上,對我來說,專門研究外部方法(叫'+ ='的方法)可能已經通過允許抖動執行單態緩存內聯向我們購買了顯着的加速。這是你想到的嗎? – 2013-04-30 22:10:40
我的觀點(這是我的另一個帳戶)是有一大堆專門的'ArrayBuilder'子類,稱爲'of'','Double'等等。當你詢問'Array.newBuilder [someprimitive]'時,會使用它們,但是你也可以直接實例化它們。如果你使用'newBuilder',你會得到一個沒有專門化的'ArrayBuilder',但是如果你實例化一個新的ArrayBuilder.ofInt(),你也會得到對'+ ='的無箱調用,這就是我正在嘗試的捕捉以上。你可以用更具體和更不具體的類型來註釋'new ofInt()'來測試它,看看你是否得到了一個裝箱調用。 – copumpkin 2013-04-30 23:53:14