问题
VectorBuilder
is defined in the same source file as Vector
. Vector
is immutable and in the scala.collections.immutable package, so as a consequence the builder is in the same package.
As far as I can tell, CanBuildFrom
uses a VectorBuilder
as the default, if the return type is not explicitly typed.
- Is there a reason for not having the builder in a separate file in the mutable package?
- Is the builder not meant to be used directly? If so, which builder or buffer is to be used to create a
Seq
?
回答1:
VectorBuilder
is not meant to be used directly. If you want to get a builder for a Vector
, you only need to call Vector.newBuilder[T]
, which returns a Builder[T, Vector[T]]
(with the underlying instance being a VectorBuilder
).
So if you want the default builder that would be used to create a Seq
, you only need to call Seq.newBuilder
:
scala> Seq(1,2,3)
res0: Seq[Int] = List(1, 2, 3)
scala> Seq.newBuilder[Int]
res1: scala.collection.mutable.Builder[Int,Seq[Int]] = ListBuffer()
scala> Seq.newBuilder[Int].result
res2: Seq[Int] = List()
The above shows that the default implementation of Seq
is list, and, logically, the default builder for a Seq
is actually a mutable.ListBuffer
.
ListBuffer
is more than just a List
builder, that's why it is in collection.mutable
whereas VectorBuilder
is not a Buffer
, it cannot be used for anything else other than build a Vector
. That's probably why it is defined locally in Vector
. I am not sure why it isn't private
, I cannot see it referenced anywhere in the public API of Vector
itself. Maybe it should be (private).
Just for reference, there is no hidden magic happening with CanBuildFrom
, it almost always just goes through the newBuilder
above:
When you do not specify the expected collection type, as in
Seq(1,2).map(_+1)
, the only availableCanBuildFrom
comes from the companion object aSeq
, and is of typeCanBuildFrom[Seq[_], T, Seq[T]]
. That means the result will be aSeq
too.Like most companion objects of collections, the
CanBuildFrom
instanceSeq
provides only does one thing: callSeq.newBuilder
(that's defined in GenTraversableFactory ...)
That's why CanBuildFrom
for Vector
uses a VectorBuilder
. For example, in this:
scala> Vector(1,2,3).map(_+1)
res12: scala.collection.immutable.Vector[Int] = Vector(2, 3, 4)
The builder that was used is:
scala> implicitly[CanBuildFrom[Vector[Int], Int, Vector[Int]]].apply()
res13: scala.collection.mutable.Builder[Int,Vector[Int]] =
scala.collection.immutable.VectorBuilder@43efdf93
回答2:
There is no mutable Vector. By analogy to ListSetBuilder
, the builder stays close to what it is building.
mutable.StringBuilder
is anomalous because it is a frequently used type that is more first-class, and tends to get passed through API. (It receives mention in the collections overview and doesn't require an import. In fact, it plays a role in this puzzler because it is subtly different from the Java StringBuilder
but you might forget that you're using it.)
VectorBuilder
is public API. The newBuilder
on companion objects has more to do with the collection factory framework and CanBuildFrom
. Neither is mentioned in the overview where it explains how to make things. I don't recall any snippets that suggest:
(ListBuffer.newBuilder[String] += "hello" += "world").result.toList
How you create a Vector
depends on what you're doing, but the overview suggests the factory methods on the companion. If you already have a collection (maybe non-strict), then toVector
. How do you make any collection of anything?
This is a good Q&A on choosing Vector over List for your Seq.
As an implementation detail, that VectorPointer
thing you see in the scaladoc includes a big comment:
// USED BY BUILDER
Since VectorPointer
is private[immutable]
, builder must stay there as a practical matter. That also suggests some thought was given as to what to expose as API.
In addition, Vector
bears a similar comment:
// in principle, most members should be private. however, access privileges must
// be carefully chosen to not prevent method inlining
These comments suggest that access levels are not haphazard.
This question is an interesting opportunity to think about the design of the package. It may be that Scala collections are a Rorschach inkblot test, revealing great beauty and symmetry, while at the same time, to the disturbed mind, a great imbalance in the universe. (Kind of kidding there.)
来源:https://stackoverflow.com/questions/17599652/why-is-vectorbuilder-in-the-package-scala-collections-immutable