看着
val sb = Seq.newBuilder[Int]
println(sb.getClass.getName)
sb += 1
sb += 2
val s = sb.result()
println(s.getClass.getName)
输出
scala.collection.mutable.ListBuffer
scala.collection.immutable。$ colon $ colon
使用Scala 2.10.1。
我希望Seq.newBuilder
返回VectorBuilder
例如。如果结果明确键入CanBuildFrom
:
Seq
会返回此消息
def build[T, C <: Iterable[T]](x: T, y: T)
(implicit cbf: CanBuildFrom[Nothing, T, C]): C = {
val b = cbf()
println(b.getClass.getName)
b += x
b += y
b.result()
}
val s: Seq[Int] = build(1, 2)
println(s.getClass.getName) // scala.collection.immutable.Vector
在这种情况下,构建器是VectorBuilder
,结果的类是Vector
。
所以我明确地希望构建一个Seq
,但结果是List
需要更多RAM,根据Scala collection memory footprint characteristics。
那么为什么Seq.newBuilder
会返回一个ListBuffer
,最终给出List
?
答案 0 :(得分:6)
Scala Collections API非常复杂,其层次结构非常丰富。每个级别代表某种新的抽象。 Seq
特征分为两个不同的子特征,它们对性能提供不同的保证(ref.):
IndexedSeq
提供元素的快速随机访问和快速长度操作。这个IndexedSeq
的一个代表是Vector
。
LinearSeq
仅通过head提供对第一个元素的快速访问,但也具有快速尾部操作。这个LinearSeq
的一个代表是List
。
由于Seq
的当前默认实施是List
,Seq.newBuilder
将返回ListBuffer
。但是,如果您想使用Vector
,可以使用Vector.newBuilder[T]
或IndexedSeq.newBuilder[T]
:
scala> scala.collection.immutable.IndexedSeq.newBuilder[Int]
res0: scala.collection.mutable.Builder[Int,scala.collection.immutable.IndexedSeq[Int]] = scala.collection.immutable.VectorBuilder@1fb10a9f
scala> scala.collection.immutable.Vector.newBuilder[Int]
res1: scala.collection.mutable.Builder[Int,scala.collection.immutable.Vector[Int]] = scala.collection.immutable.VectorBuilder@3efe9969
答案 1 :(得分:3)
默认Seq
实施是List
:
Seq(1, 2, 3) // -> List(1, 2, 3)
...因此ListBuffer
是正确的构建者。如果您需要Vector
,请使用Vector.newBuilder
或IndexedSeq.newBuilder
。
答案 2 :(得分:1)
-Yinfer-debug
反例启用CanBuildFrom
,
[search] $line14.$read.$iw.$iw.build[scala.this.Int, Seq[scala.this.Int]](1, 2) with pt=generic.this.CanBuildFrom[scala.this.Nothing,scala.this.Int,Seq[scala.this.Int]] in module class $iw, eligible:
fallbackStringCanBuildFrom: [T]=> generic.this.CanBuildFrom[String,T,immutable.this.IndexedSeq[T]]
[solve types] solving for T in ?T
inferExprInstance {
tree scala.this.Predef.fallbackStringCanBuildFrom[T]
tree.tpe generic.this.CanBuildFrom[String,T,immutable.this.IndexedSeq[T]]
tparams type T
pt generic.this.CanBuildFrom[scala.this.Nothing,scala.this.Int,Seq[scala.this.Int]]
targs scala.this.Int
tvars =?scala.this.Int
}
[search] considering no tparams (pt contains no tvars) trying generic.this.CanBuildFrom[String,scala.this.Int,immutable.this.IndexedSeq[scala.this.Int]] against pt=generic.this.CanBuildFrom[scala.this.Nothing,scala.this.Int,Seq[scala.this.Int]]
[success] found SearchResult(scala.this.Predef.fallbackStringCanBuildFrom[scala.this.Int], ) for pt generic.this.CanBuildFrom[scala.this.Nothing,scala.this.Int,Seq[scala.this.Int]]
[infer implicit] inferred SearchResult(scala.this.Predef.fallbackStringCanBuildFrom[scala.this.Int], )
实际上,
implicit def fallbackStringCanBuildFrom[T]: CanBuildFrom[String, T, immutable.IndexedSeq[T]] =
new CanBuildFrom[String, T, immutable.IndexedSeq[T]] {
def apply(from: String) = immutable.IndexedSeq.newBuilder[T]
def apply() = immutable.IndexedSeq.newBuilder[T]
}
你是什么意思,你的Iterable不是String?
trait CanBuildFrom[-From, -Elem, +To]
无论是Nothing还是Any,都是邪恶的。
编辑:对不起,我错过了,我看到你没有明确告诉它。
更新
由于CBF在From
中是逆变的,因此来自String
的CBF充当来自Nothing
的CBF。
scala> typeOf[CanBuildFrom[Nothing,Int,Seq[Int]]] <:< typeOf[CanBuildFrom[String,Int,Seq[Int]]]
res0: Boolean = false
scala> typeOf[CanBuildFrom[String,Int,Seq[Int]]] <:< typeOf[CanBuildFrom[Nothing,Int,Seq[Int]]]
res1: Boolean = true
例如,如果您需要使用immutable.Map
进行构建,则需要collection.Map
的CBF才能正常工作。
正如其他人评论的那样,Nothing
只是奇怪。但是你得到了你所要求的。也就是说,你没有明确指出,这意味着你不太关心你得到什么,Vector或其他什么。
答案 3 :(得分:0)
我同意这很奇怪。你为什么不只使用Vector.newBuilder
,如果那就是你要找的东西?
scala> val sb = Vector.newBuilder[Int]
sb: scala.collection.mutable.Builder[Int,scala.collection.immutable.Vector[Int]] = scala.collection.immutable.VectorBuilder@1fb7482a
scala> println(sb.getClass.getName)
scala.collection.immutable.VectorBuilder
scala> sb += 1
res1: sb.type = scala.collection.immutable.VectorBuilder@1fb7482a
scala> sb += 2
res2: sb.type = scala.collection.immutable.VectorBuilder@1fb7482a
scala> val s = sb.result()
s: scala.collection.immutable.Vector[Int] = Vector(1, 2)
scala> println(s.getClass.getName)
scala.collection.immutable.Vector