collezioni Arricchimento Scala con un metodo
-
26-10-2019 - |
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.
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) =>
/* ... */
}