Original
Maybe because toString.map
uses WrappedString
implicitly, and toString.toArray.map
uses WrappedArray
implicitly to resolve the map
.
Let's see the map
as defined in the TraversableLike
:
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = { val b = bf(repr) b.sizeHint(this) for (x <- this) b += f(x) b.result }
WrappedString
uses the StringBuilder
constructor as:
def +=(x: Char): this.type = { append(x); this } def append(x: Any): StringBuilder = { underlying append String.valueOf(x) this }
Calling String.valueOf
for Any
uses the Java Object.toString
in Char
instances, perhaps by first inserting a box. These additional operations may cause a difference in speed compared to the supposedly shorter code tracks of the Array constructor.
This assumption, however, would have to measure.
Edit
After the revision, the common point is still there, but I was referring to incorrect implications, as the toDigit
methods return an Int sequence (or the like) and not a translated string, as I read incorrectly.
toDigit
uses LowPriorityImplicits.fallbackStringCanBuildFrom[T]: CanBuildFrom[String, T, immutable.IndexedSeq[T]]
, with T = Int
, which simply jumps to the general IndexedSeq constructor.
toDigitFast
uses a direct array of implicit type CanBuildFrom[Array[_], T, Array[T]]
, which is undeniably faster.
Passing the following CBF to toDigit
explicitly makes these two methods equal:
object FastStringToArrayBuild { def canBuildFrom[T : ClassManifest] = new CanBuildFrom[String, T, Array[T]] { private def newBuilder = scala.collection.mutable.ArrayBuilder.make() def apply(from: String) = newBuilder def apply() = newBuilder } }