我偶然发现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
}
但它似乎微不足道,以至于我无法相信自从该语言存在以来,我发现了自己。我很想为此开一个问题,但是如果我错过任何不做我建议的理由,请告诉我!
答案 0 :(得分:3)
我认为你误解了apply(from)
的目的。
它的文件说:
根据集合的要求创建新的构建器 @param from 请求创建构建器的集合 @return 具有元素类型的
To
类型集合的构建器Elem
。集合框架通常安排 事情,以便创建的构建器将构建相同的 一种集合为from
。
因此,它用于使用集合的运行时类型来解析构建器,并且可能从原始集合中复制一些辅助数据。例如,scala.collection.generic.GenTraversableFactory#GenericCanBuildFrom
中的实现只是def apply(from: Coll) = from.genericBuilder[A]
。如您所见,没有从参数集合中复制实际数据。
实际上,CanBuildFrom
的实施会对map
,flatMap
和其他通用函数的标准实现产生错误的结果:
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