Обогащение коллекций Scala методом - PullRequest
4 голосов
/ 26 июля 2011

Как добавить метод 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)

Как мне заставить его работать без явного примененияметод конвертации?Спасибо.

Ответы [ 3 ]

8 голосов
/ 26 июля 2011

Вам необходимо расширить 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)

Для получения дополнительной информации см. этот пост Рекс Керр

4 голосов
/ 26 июля 2011

Короткий ответ заключается в том, что вы должны параметризировать CC, если вы делаете это таким образом, или средство вывода типов не может понять, что такое A. Другой короткий ответ: сделайте это так, как я описал в ответе на этот вопрос .

Чтобы немного расширить, на самом деле нет причины, по которой вам нужно CC <: TraversableLike - просто возьмите Traversable и начните с iforeach[A](coll: Traversable[A])! Вам не нужно использовать причудливые границы типов, чтобы использовать суперкласс / супертрейт. Если вы хотите сделать что-то более сложное, когда вы возвращаете другую коллекцию с сохраненным типом коллекции, вам нужно использовать компоновщики и тому подобное, что я опишу в другом вопросе.

2 голосов
/ 26 июля 2011

Если вас интересует только итерация с индексом, вы можете просто пропустить всю часть сутенерства и сделать что-то вроде

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