Scala 如何使用我自己的通用映射来丰富TraversableOnce?

Scala 如何使用我自己的通用映射来丰富TraversableOnce?,scala,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(li

我试图丰富所有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)
2.10的一般解决方案 您应该使用
感叹[That](隐式bf:CanBuildFrom[R,String,That])
而不是
CanBuildFrom[R,String,R]
。还请注意,有一种更通用的方法来扩展类集合-
IsTraversableOnce
(还有
IsTraversableLike

此方法适用于
数组

Array("a","b","c").exclaim
// Array[String] = Array(a, b, c)
固定的初始实现 这是您的初始实现(已修复)。它与
迭代器
一起工作,但在
数组
上失败,因为
数组
不是
可遍历的一次

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
                                 ^
要获得
迭代器
,您必须创建自己的隐式
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()
}
不,您将获得
迭代器[String]
而不是
可遍历一次[String]

List("a","b","c").iterator.exclaim
// Iterator[String] = non-empty iterator
您应该将隐式
iteratorCbf
方法添加到您的
equiremer
类的伴生对象中。

2.10的通用解决方案 您应该使用
感叹[That](隐式bf:CanBuildFrom[R,String,That])
而不是
CanBuildFrom[R,String,R]
。还请注意,有一种更通用的方法来扩展类集合-
IsTraversableOnce
(还有
IsTraversableLike

此方法适用于
数组

Array("a","b","c").exclaim
// Array[String] = Array(a, b, c)
固定的初始实现 这是您的初始实现(已修复)。它与
迭代器
一起工作,但在
数组
上失败,因为
数组
不是
可遍历的一次

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
                                 ^
要获得
迭代器
,您必须创建自己的隐式
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()
}
不,您将获得
迭代器[String]
而不是
可遍历一次[String]

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

您应该将隐式
iteratorCbf
方法添加到您的
equiremer
类的伴生对象中。

我认为,最简洁的答案是,不要试图用泛型映射来丰富TraversableOnce。TraversableOnce的意义在于它涵盖了迭代器和集合——但一般来说,丰富TraversableOnce(使用Scala 2.10)的唯一方法是将迭代器转换为集合,然后再转换为迭代器,这就破坏了迭代器的意义(或者至少有一点:能够流式传输巨大的数据集,而无需将它们全部加载到内存中)

我曾天真地认为,由于Iterator.map和Collection.map具有相同的语法,它们有一个共同的实现,因此我试图为我的感叹器映射找到一个共同的实现。但是,查看Scala源代码,我们发现Iterator.map和Collection.map有不同的实现:

// Implementation of map in TraversableOnce[+A] implicit typecast to MonadOps[+A]
def map[B](f: A => B): TraversableOnce[B] = trav.toIterator map f

// Implementation of map in Iterator[+A]
def map[B](f: A => B): Iterator[B] = new AbstractIterator[B] {
  def hasNext = self.hasNext
  def next() = f(self.next())
}

// Implementation of map in TraversableLike[+A, +Repr]
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
  def builder = { // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
    val b = bf(repr)
    b.sizeHint(this)
    b
  }
  val b = builder
  for (x <- this) b += f(x)
  b.result
}
//在TraversableOnce[+A]隐式类型转换中实现映射到MonadOps[+A]
定义映射[B](f:A=>B):可遍历一次[B]=trav.toIterator映射f
//在迭代器[+A]中实现映射
defmap[B](f:A=>B):迭代器[B]=新的抽象迭代器[B]{
def hasNext=self.hasNext
def next()=f(self.next())
}
//在TraversableLike[+A,+Repr]中实现map
defmap[B,That](f:A=>B)(隐式bf:CanBuildFrom[Repr,B,That]):That={
def builder={//提取以将方法大小保持在35字节以下,以便它可以JIT内联
val b=bf(报告)
b、 sizeHint(本)
B
}
val b=生成器

对于(x,我认为最清晰的答案是,不要试图用泛型映射来丰富TraversableOnce。TraversableOnce的要点是它涵盖了迭代器和集合——但这是泛型丰富TraversableOnce的唯一方法(使用Scala 2.10)就是将迭代器转换为一个集合,然后再转换为迭代器,这就破坏了迭代器的作用(或者至少有一点:能够在不将大量数据集全部加载到内存的情况下对其进行流式处理)

我曾天真地认为,由于Iterator.map和Collection.map具有相同的语法,它们有一个共同的实现,因此我试图为我的感叹器映射找到一个共同的实现。但是,查看Scala源代码,我们发现Iterator.map和Collection.map有不同的实现:

// Implementation of map in TraversableOnce[+A] implicit typecast to MonadOps[+A]
def map[B](f: A => B): TraversableOnce[B] = trav.toIterator map f

// Implementation of map in Iterator[+A]
def map[B](f: A => B): Iterator[B] = new AbstractIterator[B] {
  def hasNext = self.hasNext
  def next() = f(self.next())
}

// Implementation of map in TraversableLike[+A, +Repr]
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
  def builder = { // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
    val b = bf(repr)
    b.sizeHint(this)
    b
  }
  val b = builder
  for (x <- this) b += f(x)
  b.result
}
//在TraversableOnce[+A]隐式类型转换中实现映射到MonadOps[+A]
定义映射[B](f:A=>B):可遍历一次[B]=trav.toIterator映射f
//在迭代器[+A]中实现映射
defmap[B](f:A=>B):迭代器[B]=新的抽象迭代器[B]{
def hasNext=self.hasNext
def next()=f(self.next())
}
//在TraversableLike[+A,+Repr]中实现map
defmap[B,That](f:A=>B)(隐式bf:CanBuildFrom[Repr,B,That]):That={
def builder={//提取以将方法大小保持在35字节以下,以便它可以JIT内联
val b=bf(报告)
b、 sizeHint(本)
B
}
val b=生成器

对于(x),当我输入第二个感叹器(您的初始实现的固定版本)时,我得到一个不同的结果:List(“a”、“b”、“c”)。iterator.explorim为我返回一个可遍历的[String]。我需要做什么,使它返回一个迭代器[String]?(我刚刚意识到我使用的是Scala 2.9.3,如果这有区别的话。)@DamonJW:我在
2.10.3
上获得了
Iterator[String]
,而
2.9.3
中没有
IsTraversableOnce
,所以是的,这会产生不同。我现在无法升级到2.10。你知道我是否可以从[Iterator,\uu,Iterator]中提取一些东西来为我提供CanBuildFrom[Iterator]我需要?@DamonJW:我现在正试图在
2.9.3
上修复它,但我想这几乎是不可能的。你可以从[Iterator,u,Iterator]
创建自己的隐式
CanBuildFrom,但这不是一个通用的解决方案。@DamonJW:实际上这个解决方案还不错,你应该使用你的实现(固定版本)在作用域中使用隐式的
CanBuildFrom[Iterator,u,Iterator]