Обогащение коллекций Scala методом
-
26-10-2019 - |
Вопрос
Как добавить 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)
Как заставить его работать без явного применения метода преобразования? Спасибо.
Решение
Вам нужно продлить итеральную:
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)
Видеть этот пост Рекса Керра Чтобы получить больше информации.
Другие советы
Краткий ответ в том, что вам нужно параметризировать CC
Если вы делаете это так или тот тип Inferencer не может понять, что A
является. Другой короткий ответ - сделать так, как я опишу в ответе на этот вопрос.
Чтобы расширить немного больше, на самом деле нет причин, по которой вам нужно CC <: TraversableLike
-просто возьмите это Traversable
И начните с iforeach[A](coll: Traversable[A])
! Вам не нужно использовать причудливые границы типа, чтобы использовать Superclass/Supertrait. Если вы хотите сделать что -то более сложное, когда вы возвращаете еще одну коллекцию с сохранением типа коллекции, то вам нужно использовать строителей и тому подобное, которое я описываю в другом вопросе.
Если то, что вас интересует, является только итерацией с индексом, вы можете просто пропустить всю сутенерскую часть и сделать что -то вроде
coll.zipWithIndex.foreach { case (elem, index) =>
/* ... */
}