如何使用我自己的通用地图丰富 TraversableOnce? [英] How to enrich a TraversableOnce with my own generic map?
问题描述
我正在尝试丰富所有 TraversableOnce[String] 对象,但我无法找出构建迭代器的正确语法.这是我目前所拥有的:
I am trying to enrich all TraversableOnce[String] objects, and I can't figure out the right syntax for building iterators. This is what I have so far:
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)
它适用于集合(即它返回一个与我给它的类相同的集合),但它不适用于迭代器,因为它不能构造一个 Iterator[java.lang 类型的集合.String] 具有基于 Iterator[java.lang.String] 类型的集合的 String 类型元素
.我该如何解决?我使用的是 Scala 2.9(我错误地写了 2.8).
It works fine for collections (i.e. it returns an collection of the same class as I gave it), but it doesn't work for iterators, because it 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]
. How do I fix this? I'm using Scala 2.9 (edit: I mistakenly wrote 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
^
推荐答案
2.10通用解决方案
你应该使用 exclaim[That](implicit bf:CanBuildFrom[R, String, That])
而不是 CanBuildFrom[R,String,R]
.另请注意,有更通用的方法来扩展类集合 - IsTraversableOnce
(以及 IsTraversableLike
)
General solution for 2.10
You should use exclaim[That](implicit bf:CanBuildFrom[R, String, That])
instead of CanBuildFrom[R,String,R]
. Note also that there is more general way to extend collection-like classes - IsTraversableOnce
(and also 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))
此方法适用于Array
:
Array("a","b","c").exclaim
// Array[String] = Array(a, b, c)
修复了初始实现
这是您的初始实现(已修复).它适用于 Iterator
,但在 Array
上失败,因为 Array
不是 TraversableOnce
:
Fixed initial implementation
Here is your initial implementation (fixed). It works with Iterator
, but fails on Array
since Array
is not 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
^
CanBuildFrom
scala
2.9.3
中没有 IsTraversableOnce
,因此您必须使用初始方法的固定版本.但是你会得到 TraversableOnce
而不是 Iterator
.
CanBuildFrom
There is no IsTraversableOnce
in scala
2.9.3
, so you have to use fixed version of your initial approach. But you'll get TraversableOnce
instead of Iterator
.
List("a","b","c").iterator.exclaim
// scala.collection.TraversableOnce[String] = non-empty iterator
要获得 Iterator
,您必须像这样创建自己的隐式 CanBuildFrom
:
To get Iterator
you have to create your own implicit CanBuildFrom
like this:
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()
}
不,你会得到 Iterator[String]
而不是 TraversableOnce[String]
:
No you'll get Iterator[String]
instead of TraversableOnce[String]
:
List("a","b","c").iterator.exclaim
// Iterator[String] = non-empty iterator
您应该将隐式 iteratorCbf
方法添加到您的 Exclaimer
类的伴随对象中.
You should add implicit iteratorCbf
method into companion object of your Exclaimer
class.
这篇关于如何使用我自己的通用地图丰富 TraversableOnce?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!