Pregunta

¿Cómo agrego un foreachWithIndex método en colecciones de Scala?

Esto es lo que se me ocurrió hasta ahora:

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

Esto no funciona:

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

Plantea el siguiente error:

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

Sin embargo, el código funciona cuando aplico explícitamente el método de conversión:

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

Producción:

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

¿Cómo hago que lo haga funcionar sin la aplicación explícita de un método de conversión? Gracias.

¿Fue útil?

Solución

Necesitas extender 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)
}

producción:

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

Ver Esta publicación de Rex Kerr para más información.

Otros consejos

La respuesta corta es que tienes que parametrizar CC Si lo hace de esa manera o el tipo de infierno no puede entender qué A es. La otra respuesta corta es que lo haga como describo en la respuesta a esta pregunta.

Para expandirse un poco más, realmente no hay razón para que necesite CC <: TraversableLike-solo tener que tome un Traversable y empezar con iforeach[A](coll: Traversable[A])! No necesita usar límites de tipo elegante para usar una superclase/supertrait. Si desea hacer algo más complicado cuando devuelva otra colección con el tipo de colección conservado, entonces debe usar constructores y demás, que describo en la otra pregunta.

Si lo que le interesa solo está iterando con un índice, también podría omitir toda la parte de proxeneta y hacer algo como

coll.zipWithIndex.foreach { case (elem, index) =>
  /* ... */
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top