使用方法丰富Scala集合

时间:2011-07-25 22:37:44

标签: scala implicit-conversion scala-collections enrich-my-library

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

这是我到目前为止所能提出的:

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)

如果没有明确应用转换方法,如何让它工作?感谢。

3 个答案:

答案 0 :(得分: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)

有关详细信息,请参阅this post by Rex Kerr

答案 1 :(得分:4)

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

为了进一步扩展,您确实没有理由需要CC <: TraversableLike - 只需要Traversable并从iforeach[A](coll: Traversable[A])开始!您不需要使用花式类型边界来使用超类/超级类。如果你想做一些更复杂的事情,你返回另一个集合类型保留的集合,那么你需要使用构建器等,我在另一个问题中描述。

答案 2 :(得分:2)

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

的操作
coll.zipWithIndex.foreach { case (elem, index) =>
  /* ... */
}