How do I add a foreachWithIndex
method on Scala collections?
This is what I could come up with so fa开发者_JAVA技巧r:
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.
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.
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.
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) =>
/* ... */
}
精彩评论