4

如何foreachWithIndex在 Scala 集合上添加方法?

到目前为止,这是我能想到的:

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
    }
  }
}

这不起作用:

Vector(9, 11, 34).foreachWithIndex { (el, i) =>
  println(el, i)
}

引发以下错误:

error: value foreachWithIndex is not a member of scala.collection.immutable.Vector[Int]
Vector(9, 11, 34).foreachWithIndex { (el, i) =>

但是,当我明确应用转换方法时,代码可以工作:

iforeach[Int, Vector[Int]](Vector(9, 11, 34)).foreachWithIndex { (el, i) =>
  println(el, i)
}

输出:

(9,0)
(11,1)
(34,2)

如何在不显式应用转换方法的情况下使其工作?谢谢。

4

3 回答 3

8

您需要扩展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)
}

输出:

(9,0)
(11,1)
(34,2)

有关更多信息,请参阅Rex Kerr 的这篇文章

于 2011-07-25T22:56:55.903 回答
4

简短的回答是,如果你这样做,你必须参数化CC,否则类型推断器无法弄清楚是什么A。另一个简短的答案是按照我在这个问题的答案中描述的方式进行。

再扩展一点,你真的没有理由需要-CC <: TraversableLike只需 aTraversable并从iforeach[A](coll: Traversable[A])! 您不需要使用花哨的类型边界来使用超类/超特征。如果您想做一些更复杂的事情,即返回另一个保留了集合类型的集合,那么您需要使用构建器等,我在另一个问题中对此进行了描述。

于 2011-07-25T22:56:18.177 回答
2

如果您感兴趣的只是使用索引进行迭代,那么您不妨跳过整个拉皮条部分并执行类似的操作

coll.zipWithIndex.foreach { case (elem, index) =>
  /* ... */
}
于 2011-07-25T23:05:38.770 回答