为什么在Scala的标准库中专门有这么几件事?
我已经在Scala 2.8.1的标准库的源代码中search了@specialized
的用法。 它看起来只有less数的特征和类使用这个注释: Function0
, Function1
, Function2
, Tuple1
, Tuple2
, Product1
, Product2
, AbstractFunction0
, AbstractFunction1
, AbstractFunction2
。
没有任何集合类是@specialized
。 为什么不? 这会产生太多类吗?
这意味着使用具有原始types的集合类是非常低效的,因为会有大量不必要的装箱和拆箱操作。
什么是最有效的方法来有一个不变的列表或序列(与IndexedSeq
特性)的Int
,避免装箱和拆箱?
专业化对class级规模的成本很高,因此必须加以慎重考虑。 在collections品的特殊情况下,我认为这种影响将是巨大的。
不过,这是一个持续的努力 – 斯卡拉图书馆几乎没有开始专业化。
在类的大小和编译时间方面,专门化可能是昂贵的( 指数的 )。 它不只是接受的答案的大小说。
打开你的Scala REPL并input这个。
import scala.{specialized => sp} trait S1[@sp A, @sp B, @sp C, @sp D] { def f(p1:A): Unit }
对不起:-) 它就像一个编译器炸弹。
现在,让我们拿一个简单的特质
trait Foo[Int]{ }
以上将导致两个编译类。 Foo,纯粹的接口和Foo $ 1,类的实现。
现在,
trait Foo[@specialized A] { }
一个专门的模板参数在这里被扩展/重写了9种不同的基本types(void,boolean,byte,char,int,long,short,double,float)。 所以,基本上你最终会有20个class,而不是2个。
回到具有5个特定模板参数的特征,为每种可能的基元types的组合生成类。 即其复杂度指数。
2 * 10 ^ (没有专门的参数)
如果你正在为一个特定的基本types定义一个类,你应该更加明确的如
trait Foo[@specialized(Int) A, @specialized(Int,Double) B] { }
可以理解的是,在构build通用库时,必须要使用专门的节约。
保罗·菲利普斯咆哮着。
部分回答我自己的问题:我可以像这样在一个IndexedSeq
包装一个数组:
import scala.collection.immutable.IndexedSeq def arrayToIndexedSeq[@specialized(Int) T](array: Array[T]): IndexedSeq[T] = new IndexedSeq[T] { def apply(idx: Int): T = array(idx) def length: Int = array.length }
(当然你仍然可以修改内容,如果你有权访问底层数组,但我会确保数组不会传递到我的程序的其他部分)。