问题
How do I add a foreachWithIndex
method on Scala collections?
This is what I could come up with so far:
implicit def iforeach[A, CC <: TraversableLike[A, CC]](coll: CC) = new {
def foreachWithIndex[B](f: (A, Int) => B): Unit = {
var i = 0
for (c <- coll) {
f(c, i)
i += 1
}
}
}
This doesn't work:
Vector(9, 11, 34).foreachWithIndex { (el, i) =>
println(el, i)
}
Raises the following error:
error: value foreachWithIndex is not a member of scala.collection.immutable.Vector[Int]
Vector(9, 11, 34).foreachWithIndex { (el, i) =>
However the code works when I explicitly apply the conversion method:
iforeach[Int, Vector[Int]](Vector(9, 11, 34)).foreachWithIndex { (el, i) =>
println(el, i)
}
Output:
(9,0)
(11,1)
(34,2)
How do I make it make it work without explicit application of a conversion method? Thanks.
回答1:
You need to extend Iterable:
class RichIter[A, C](coll: C)(implicit i2ri: C => Iterable[A]) {
def foreachWithIndex[B](f: (A, Int) => B): Unit = {
var i = 0
for (c <- coll) {
f(c, i)
i += 1
}
}
}
implicit def iter2RichIter[A, C[A]](ca: C[A])(
implicit i2ri: C[A] => Iterable[A]
): RichIter[A, C[A]] = new RichIter[A, C[A]](ca)(i2ri)
Vector(9, 11, 34) foreachWithIndex {
(el, i) => println(el, i)
}
output:
(9,0)
(11,1)
(34,2)
See this post by Rex Kerr for more information.
回答2:
The short answer is that you have to parameterize CC
if you do it that way or the type inferencer can't figure out what A
is. The other short answer is do it the way I describe in the answer to this question.
To expand a little bit more, there's really no reason that you need CC <: TraversableLike
--just have it take a Traversable
and start with iforeach[A](coll: Traversable[A])
! You don't need to use fancy type bounds in order to use a superclass/supertrait. If you want to do something more complicated where you return another collection with collection type preserved, then you need to use builders and such, which I describe in the other question.
回答3:
If what you're interested in is only iterating with an index, you might as well just skip the whole pimping part and do something like
coll.zipWithIndex.foreach { case (elem, index) =>
/* ... */
}
来源:https://stackoverflow.com/questions/6823213/enriching-scala-collections-with-a-method