Predef.StringCanBuildFrom的行为

时间:2017-01-22 00:29:13

标签: scala

我偶然发现Predef.StringCanBuildFrom令人惊讶的实施,这打破了我在代码中对CanBuildFrom做出的假设。这是实施:

implicit def stringCanBuildFrom: CanBuildFrom[String, Char, String] = 
    new CanBuildFrom[String, Char, String] {
      def apply(from: String) = apply()
      def apply() = mutable.StringBuilder.newBuilder
}

apply(String)完全忽略参数似乎完全不自然。对我来说,正确的实现应该是

implicit def stringCanBuildFrom: CanBuildFrom[String, Char, String] = 
    new CanBuildFrom[String, Char, String] {
      def apply(from: String) = apply() ++= from
      def apply() = mutable.StringBuilder.newBuilder
}

但它似乎微不足道,以至于我无法相信自从该语言存在以来,我发现了自己。我很想为此开一个问题,但是如果我错过任何不做我建议的理由,请告诉我!

1 个答案:

答案 0 :(得分:3)

我认为你误解了apply(from)的目的。

它的文件说:

  

根据集合的要求创建新的构建器    @param from 请求创建构建器的集合    @return 具有元素类型的To类型集合的构建器   Elem。集合框架通常安排   事情,以便创建的构建器将构建相同的   一种集合为from

因此,它用于使用集合的运行时类型来解析构建器,并且可能从原始集合中复制一些辅助数据。例如,scala.collection.generic.GenTraversableFactory#GenericCanBuildFrom中的实现只是def apply(from: Coll) = from.genericBuilder[A]。如您所见,没有从参数集合中复制实际数据。

实际上,CanBuildFrom的实施会对mapflatMap和其他通用函数的标准实现产生错误的结果:

import scala.collection.generic.CanBuildFrom
import scala.collection.mutable

implicit def stringCanBuildFrom: CanBuildFrom[String, Char, String] =
  new CanBuildFrom[String, Char, String] {
    def apply(from: String) = apply() ++= from
    def apply() = mutable.StringBuilder.newBuilder
  }

scala> "foo".map(identity)(stringCanBuildFrom)
res1: String = foofoo