43

我在@specializedScala 2.8.1的标准库的源代码中搜索了使用。看起来只有少数特征和类使用此注释:Function0, Function1, Function2, Tuple1, Tuple2, Product1, Product2, AbstractFunction0, AbstractFunction1, AbstractFunction2

集合类都不是@specialized. 为什么不?这会产生太多的类吗?

这意味着使用原始类型的集合类是非常低效的,因为会有很多不必要的装箱和拆箱。

拥有 s的不可变列表或序列(具有IndexedSeq特征)的最有效方法是什么Int,避免装箱和拆箱?

4

3 回答 3

18

专业化对班级规模的成本很高,因此必须仔细考虑添加。在收藏的特殊情况下,我想影响将是巨大的。

尽管如此,这是一项持续的努力——Scala 库才刚刚开始专门化。

于 2011-03-29T21:39:05.393 回答
17

专业化在类的大小和编译时间上都可能很昂贵(指数型)。它不仅仅是像公认的答案所说的那样大小。

打开你的 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 个专用模板参数的 trait,为每个可能的原始类型组合生成类。即它的复杂性呈指数级。

2 * 10 ^ (没有专门的参数)

如果您正在为特定的原始类型定义一个类,您应该更明确地说明它,例如

trait Foo[@specialized(Int) A, @specialized(Int,Double) B] { }

可以理解的是,在构建通用库时必须节俭使用专业。

是保罗菲利普斯对此的咆哮。

于 2013-03-08T17:57:33.387 回答
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
}

(当然,如果您可以访问底层数组,您仍然可以修改内容,但我会确保该数组不会传递给我程序的其他部分)。

于 2011-03-29T19:19:17.430 回答