我在Scala 2.8.1的标准库的源代码中搜索了@specialized
的使用。看起来只有少数特征和类使用此注释:Function0
,Function1
,Function2
,Tuple1
,Tuple2
,Product1
, Product2
,AbstractFunction0
,AbstractFunction1
,AbstractFunction2
。
所有集合类都不是@specialized
。为什么不?这会产生太多的课程吗?
这意味着使用带有基本类型的集合类效率非常低,因为会有很多不必要的装箱和拆箱。
拥有IndexedSeq
s的不可变列表或序列(具有Int
特征)的最有效方法是什么,避免装箱和拆箱?
答案 0 :(得分:18)
专业化课程的成本很高,因此必须仔细考虑。在收藏品的特殊情况下,我认为影响将是巨大的。
尽管如此,这仍是一项持续的努力 - Scala图书馆几乎没有开始专业化。
答案 1 :(得分:16)
在类的大小和编译时,Specialized可能很昂贵(指数)。它的大小不仅仅是接受的答案。
打开你的scala REPL并输入。
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种不同的基本类型(void,boolean,byte,char,int,long,short,double,float)进行扩展/重写。所以,基本上你最终会得到20个而不是2个。
回到具有5个专用模板参数的特征,为每种可能的基元类型组合生成类。即其复杂性呈指数级增长。
2 * 10 ^ (没有专门的参数)
如果要为特定基元类型定义类,则应该更加明确它,例如
trait Foo[@specialized(Int) A, @specialized(Int,Double) B] { }
可以理解的是,在构建通用库时,必须使用专业人员才能节俭。
Here是保罗菲利普斯咆哮的。
答案 2 :(得分:6)
对我自己的问题的部分回答:我可以像这样在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
}
(当然,如果你有权访问底层数组,你仍然可以修改内容,但我会确保数组不会传递给我程序的其他部分。)