开发者

Enriching Scala collections with a method

开发者 https://www.devze.com 2023-03-23 08:32 出处:网络
How do I add a foreachWithIndex method on Scala collections? This is what I could come up with so fa开发者_JAVA技巧r:

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) =>
  /* ... */
}
0

精彩评论

暂无评论...
验证码 换一张
取 消