Kutusuzluğa ulaşmak için aynı kodu tekrar tekrar yazmamak için iyi uygulamalar arıyorum. Böyle bir şey olduğunu varsayalım:Boilerplate içermeyen Scala ArrayBuilder uzmanlığı
def speedyArrayMaker[@specialized(Long) A: ClassTag](...): Array[A] = {
val builder = Array.newBuilder[A]
// do stuff with builder
builder.result
}
Bu altta yatan kutulanmamış depolama sonuçlanacaktır benim builder
mümkün olduğunda ancak anladığım kadarıyla ben unspecialized ArrayBuilder
özelliği gidiyorum çünkü hiçbir kutulanmamış yöntem kendisine çağırır. Bir monomorfik dünyada
Long
için uzmanlaşmış, ben çoğaltma önlemek için güzel bir yol düşünemiyorum, val builder = new ArrayBuilder.ofLong()
yazmak ve tüm boks önlemek, ancak ArrayBuilder
/Builder
tüm ilkel türlerinde uzmanlaşmış edilecek anlatan kısa ediyorum buradaki çaba. Ben speedyArrayMaker
içinde olmak arasında diye düşündüm bir yaklaşım:
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)
}
biz gerçekten uzman olsun ister sadece +=
yöntem, ve sonra biz Long
üzerinde uzmanlaşmıştır add
için Function1
olsun beri. Gerçekten ben (hatta ihtisas çıktıda) Array.newBuilder[A]
versiyonu için
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;
olsun, javap ile kontrol ediliyor ve: dolambaçlı sürümü için
252: invokeinterface #204, 3; //InterfaceMethod scala/Function1.apply$mcVJ$sp:(J)V
. Bu modeli "özel oluşturucu yardımcı" işlevine dahil edebilirim, ancak özellikle uzmanlık sırasında derleme zamanında bilinen bir şeye göre çalışma zamanında gönderilirken çirkin hissediyor. Nihayetinde benim önerimin, Function1
'un zaten uzmanlaşmış olduğu gerçeğini anlatmak olduğunu söyleyebilirim ve özellikle beğenmiyorum.
Bunu daha keyifli hale getirmek için kullanabileceğim akıllı numaralar var mı? Bunun gerçekten düşük seviyeli bir ayrıntı olduğunu ve nadiren performans açısından kritik olduğunu fark ettim, ancak tüm ArrayBuilder.of*
uzmanlık sınıflarına giren çaba/kod çoğaltma miktarı göz önünde bulundurulduğunda, avantajlarından bazıları için avantajlar atmak üzücü gibi görünüyor. polimorfik olmak.
Düzenleme çirkin bir şey düşündüm ama umuyordum bu işe yarar : my uzman işlevi içinde
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]
ve sonra:
val witness: Array[A] = null
val builder = builderOf(witness)
ama genel builderOf
çağırmak gibi görünüyor özel sürümde bile (Array[Long]
versiyonunu aramak için yeterli tip bilgisi olsa bile). Bunun neden işe yaradığını bilen var mı? Yaklaşım, önerdiğim diğerine kıyasla oldukça temiz görünüyor. Sanırım uzmanlık için daha "makro gibi" bir yaklaşım umuyordum, ama sanırım her bir uzmanlık için aynı yöntemi seçmedikçe tüm örneklemelerin doğru olacağını garanti edemiyorum :(
sana yapacağım şey 'ArrayBuidler' uzman olmayan' göz önüne alındığında, size bir ihtisas almak (ve dolayısıyla nasıl görmek emin değilim, hatları (barbarca isimleri bahane) boyunca bir şey deneyebilirsiniz + = ', özel bir yöntemle çağrılsa bile asla uzmanlaşmayacaktır).ArrayBuidler'ı tamamen devre dışı bırakırsanız (yalnızca kendi özel sürümünüzü tanımlayarak) sadece uzmanlık kazanacaksınız. –
Aslında, bana, "sadece" dış yöntemi (+ + 'yi çağıran) uzmanlaşmanın, jitterin monorphic önbellek satırlaması yapmasına izin vererek, bizi önemli bir hızlandırma satın alabildiği ortaya çıktı. Aklında olan şey bu mu? –
Benim amacım (bu benim diğer hesabım) '' '' '' '' '' '' '' '' '' 'denilen bir dizi' 'ArrayBuilder' 'alt-sınıfı' 'vardır,' 'Array.newBuilder [someprimitive]' 'için istediğinizde kullanılırlar ama siz onları doğrudan da başlatabilir. Eğer 'newBuilder' kullanıyorsanız, uzman olmayan bir "ArrayBuilder" elde edersiniz, ancak "yeni bir ArrayBuilder.ofInt()" yi başlatırsanız, + + 'ya da denemediğim şeyleri alırsınız. yukarıda yakalamak için. Bunu, 'new ofInt() 'i daha spesifik ve daha az spesifik tiplerle ekleyerek ve bir boks çağrısıyla karşılaşıp karşılaşmadığınızı test edebilirsiniz. – copumpkin