如何使用我自己的通用地图丰富TraversableOnce?

Dam*_*nJW 1 scala

我试图丰富所有TraversableOnce [String]对象,我无法找出构建迭代器的正确语法.这是我到目前为止:

class Exclaimer[R <: TraversableOnce[String]](val lines:R) {
  import scala.collection.generic.CanBuildFrom
  def exclaim(implicit bf:CanBuildFrom[R,String,R]):R = {
    val b = bf(lines)
    lines.foreach(b += _)
    b.result
  }
}
implicit def WrapExclaimer[R <: TraversableOnce[String]](lines:R) = new Exclaimer(lines)
Run Code Online (Sandbox Code Playgroud)

它适用于集合(即它返回与我给它相同的类的集合),但它不适用于迭代器,因为它Cannot construct a collection of type Iterator[java.lang.String] with elements of type String based on a collection of type Iterator[java.lang.String].我该如何解决?我正在使用Scala 2.9(编辑:我错误地写了2.8).

这是一些示例输出:

scala> List("a","b","c").exclaim
res5: List[java.lang.String] = List(a, b, c)

scala> Vector("a","b","c").exclaim
res6: scala.collection.immutable.Vector[java.lang.String] = Vector(a, b, c)

scala> List("a","b","c").iterator.exclaim
<console>:10: error: Cannot construct a collection of type Iterator[java.lang.String] with elements of type String based on a collection of type Iterator[java.lang.String].
              List("a","b","c").iterator.exclaim
                                         ^
Run Code Online (Sandbox Code Playgroud)

sen*_*nia 5

2.10的一般解决方案

你应该使用exclaim[That](implicit bf:CanBuildFrom[R, String, That])而不是CanBuildFrom[R,String,R].另请注意,有更多通用的方法来扩展类似集合的类 - IsTraversableOnce(以及IsTraversableLike)

import collection.generic.IsTraversableOnce
import collection.GenTraversableOnce

class Exclaimer[A, Repr](val lines: GenTraversableOnce[A]) {
  import scala.collection.generic.CanBuildFrom
  def exclaim[That](implicit bf:CanBuildFrom[Repr, String, That], e: A =:= String): That = {
    val b = bf()
    lines.foreach(s => b += e(s))
    b.result
  }
}
implicit def wrapExclaimer[Repr](r: Repr)(implicit fr: IsTraversableOnce[Repr]): Exclaimer[fr.A,Repr] =
  new Exclaimer[fr.A, Repr](fr.conversion(r))
Run Code Online (Sandbox Code Playgroud)

此方法适用于Array:

Array("a","b","c").exclaim
// Array[String] = Array(a, b, c)
Run Code Online (Sandbox Code Playgroud)

修复了初始实现

这是您的初始实施(已修复).它适用Iterator,但失败,Array因为Array不是TraversableOnce:

class Exclaimer[R <: TraversableOnce[String]](val lines:R) {
  import scala.collection.generic.CanBuildFrom
  def exclaim[That](implicit bf:CanBuildFrom[R,String,That]):That = {
    val b = bf(lines)
    lines.foreach(b += _)
    b.result
  }
}
implicit def WrapExclaimer[R <: TraversableOnce[String]](lines:R) = new Exclaimer(lines)

scala> List("a","b","c").iterator.exclaim
res0: Iterator[String] = non-empty iterator

scala> Array("a","b","c").exclaim
<console>:10: error: value exclaim is not a member of Array[String]
              Array("a","b","c").exclaim
                                 ^
Run Code Online (Sandbox Code Playgroud)

CanBuildFrom

有没有IsTraversableOncescala 2.9.3,所以你必须使用你的初步做法的修正版本.但你会得到TraversableOnce而不是Iterator.

List("a","b","c").iterator.exclaim
// scala.collection.TraversableOnce[String] = non-empty iterator
Run Code Online (Sandbox Code Playgroud)

为了让Iterator你必须CanBuildFrom像这样创建自己的隐含:

import collection.generic.CanBuildFrom
import collection.mutable.Builder
import collection.immutable.VectorBuilder

implicit def iteratorCbf[A, B] = new CanBuildFrom[Iterator[A], B, Iterator[B]]{
  def apply(): Builder[B, Iterator[B]] = new Builder[B, Iterator[B]]{
    private[this] val inner = new VectorBuilder[B]
    def +=(elem: B) = {
      inner += elem
      this
    }
    def clear(): Unit = inner.clear()
    def result(): Iterator[B] = inner.result().iterator
  }
  def apply(i: Iterator[A]) = apply()
}
Run Code Online (Sandbox Code Playgroud)

不,你会得到Iterator[String]而不是TraversableOnce[String]:

List("a","b","c").iterator.exclaim
// Iterator[String] = non-empty iterator
Run Code Online (Sandbox Code Playgroud)

您应该将隐式iteratorCbf方法添加到Exclaimer类的伴随对象中.