如何在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)
如果没有明确应用转换方法,如何让它工作?感谢。
答案 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) =>
/* ... */
}