In breve: uno Iterator
ha lo stato, mentre uno Iterable
no.
Vedere i documenti API per entrambi.
Iterable:
Un tratto di base per le collezioni iterabili.
Questo è un tratto di base per tutte le raccolte Scala che definiscono un iteratore metodo per esaminare uno per uno gli elementi della raccolta. [...] Questa caratteristica implementa il metodo foreach di Iterable passando lo attraverso tutti gli elementi usando iteratore.
Iterator:
Iteratori sono strutture di dati che permettono di iterare su una successione di elementi . Hanno un metodo hasNext per verificare se è disponibile un elemento successivo e un metodo successivo che restituisce l'elemento successivo e lo scarta dall'iteratore.
Un iteratore è mutabile: la maggior parte delle operazioni su di esso cambiano stato. Mentre viene spesso utilizzato per scorrere gli elementi di una raccolta, è possibile utilizzare anche senza il backup di alcuna raccolta (vedere i costruttori nell'oggetto associato).
Con un Iterator
è possibile interrompere un'iterazione e proseguirla in un secondo momento, se lo si desidera. Se si tenta di fare questo con un Iterable
inizierà da ancora la testa:
scala> val iterable: Iterable[Int] = 1 to 4
iterable: Iterable[Int] = Range(1, 2, 3, 4)
scala> iterable.take(2)
res8: Iterable[Int] = Range(1, 2)
scala> iterable.take(2)
res9: Iterable[Int] = Range(1, 2)
scala> val iterator = iterable.iterator
iterator: Iterator[Int] = non-empty iterator
scala> if (iterator.hasNext) iterator.next
res23: AnyVal = 1
scala> if (iterator.hasNext) iterator.next
res24: AnyVal = 2
scala> if (iterator.hasNext) iterator.next
res25: AnyVal = 3
scala> if (iterator.hasNext) iterator.next
res26: AnyVal = 4
scala> if (iterator.hasNext) iterator.next
res27: AnyVal =()
nota, che non ho usato take
su Iterator
. La ragione di questo è che è difficile da usare. hasNext
e next
sono gli unici due metodi che sono garantiti per funzionare come previsto su Iterator
.Vedere il nuovo Scaladoc:
E 'di particolare importanza notare che, salvo diversa indicazione, non si dovrebbe mai usare un iteratore dopo aver chiamato un metodo su di esso. Le due eccezioni più importanti di sono anche i soli metodi astratti: next e hasNext.
Entrambi questi metodi possono essere chiamati un numero qualsiasi di volte senza dover annullare l'iteratore . Notare che anche hasNext può causare la mutazione - come quando si itera da un flusso di input, dove bloccherà fino a lo stream è chiuso o qualche input diventa disponibile.
Consideriamo questo esempio per un utilizzo sicuro e non sicuri:
def f[A](it: Iterator[A]) = {
if (it.hasNext) { // Safe to reuse "it" after "hasNext"
it.next // Safe to reuse "it" after "next"
val remainder = it.drop(2) // it is *not* safe to use "it" again after this line!
remainder.take(2) // it is *not* safe to use "remainder" after this line!
} else it
}
grazie, con l'esempio, ha perfettamente senso. –
Odersky e Spoon hanno scritto un buon primer sulle classi della collezione Scala: vedi http://www.scala-lang.org/docu/files/collections-api/collections.html –
Ho provato questo in Scala 2.11.7, iterator si comporta in modo simile a iterable, ovvero quando invochi 'take (2)' per la seconda volta, ottieni ancora 'List (1, 2)'. – qed