Domanda

Come faccio ad aggiungere un metodo foreachWithIndex su collezioni Scala?

Questo è quello che ho potuto venire con finora:

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

Questo non funziona:

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

Aumenta il seguente errore:

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

Tuttavia, il codice funziona quando applico in modo esplicito il metodo di conversione:

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

Output:

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

Come faccio a farlo farlo funzionare senza applicazione esplicita di un metodo di conversione? Grazie.

È stato utile?

Soluzione

È necessario estendere 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)
}

uscita:

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

questo post da Rex Kerr per ulteriori informazioni.

Altri suggerimenti

La risposta breve è che si deve parametrizzare CC se lo si fa in questo modo o il tipo inferencer non riesce a capire che cosa è A. L'altra risposta breve è farlo nel modo che descrivo nella risposta alla questa domanda .

Per espandere un po 'di più, non c'è davvero alcun motivo che è necessario CC <: TraversableLike - basta ci vuole un Traversable e iniziare con iforeach[A](coll: Traversable[A])! Non è necessario digitare l'uso di fantasia limiti al fine di utilizzare una superclasse / supertrait. Se si vuole fare qualcosa di più complicato in cui si torna un'altra raccolta con il tipo di collezione conservata, quindi è necessario utilizzare costruttori e quali, che descrivo nel altra questione.

Se state nel interessa è l'iterazione solo con un indice, si potrebbe anche solo saltare tutta la parte sfruttamento della prostituzione e fare qualcosa di simile

coll.zipWithIndex.foreach { case (elem, index) =>
  /* ... */
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top