Ho esaminato questa domanda ma ancora non capisco la differenza tra i tratti Iterable e Traversable. Qualcuno può spiegare?
Ho esaminato questa domanda ma ancora non capisco la differenza tra i tratti Iterable e Traversable. Qualcuno può spiegare?
Risposte:
Per dirla semplicemente, gli iteratori mantengono lo stato, gli attraversabili no.
Una Traversable
ha un metodo astratto: foreach
. Quando si chiama foreach
, la raccolta alimenterà alla funzione passata tutti gli elementi che conserva, uno dopo l'altro.
D'altra parte, un Iterable
ha come metodo astratto iterator
, che restituisce un Iterator
. Puoi chiamare next
un Iterator
per ottenere l'elemento successivo al momento della tua scelta. Fino a quando non lo fai, deve tenere traccia di dove si trovava nella raccolta e cosa verrà dopo.
Iterable
estende Traversable
, quindi immagino tu intenda Traversable
s che non sono Iterable
s.
Traversable
dell'interfaccia non richiede il mantenimento dello stato, mentre il rispetto Iterator
dell'interfaccia sì .
Traversable
s che sono Iterable
non mantengono alcuno stato di iterazione. È il Iterator
creato e restituito dal Iterable
che mantiene lo stato.
Pensala come la differenza tra soffiare e succhiare.
Quando si chiama una Traversable
s foreach
, o i suoi metodi derivati, soffia i suoi valori nella funzione uno alla volta, quindi ha il controllo sull'iterazione.
Con il Iterator
ritorno da un Iterable
pensiero, ne risucchi i valori, controllando tu stesso quando passare a quello successivo.
tl; dr Iterables
sono Traversables
che possono produrre statefulIterators
Innanzitutto, sappi che Iterable
è un sottotitolo di Traversable
.
Secondo,
Traversable
richiede l'implementazione del foreach
metodo, che viene utilizzato da tutto il resto.
Iterable
richiede l'implementazione del iterator
metodo, che viene utilizzato da tutto il resto.
Ad esempio, l'implementazione di find
for Traversable
utilizza foreach
(tramite una per la comprensione) e genera BreakControl
un'eccezione per arrestare l'iterazione una volta trovato un elemento soddisfacente.
trait TravserableLike {
def find(p: A => Boolean): Option[A] = {
var result: Option[A] = None
breakable {
for (x <- this)
if (p(x)) { result = Some(x); break }
}
result
}
}
Al contrario, la Iterable
sottrazione sovrascrive questa implementazione e chiama find
il Iterator
, che interrompe semplicemente l'iterazione una volta trovato l'elemento:
trait Iterable {
override /*TraversableLike*/ def find(p: A => Boolean): Option[A] =
iterator.find(p)
}
trait Iterator {
def find(p: A => Boolean): Option[A] = {
var res: Option[A] = None
while (res.isEmpty && hasNext) {
val e = next()
if (p(e)) res = Some(e)
}
res
}
}
Sarebbe bello non generare eccezioni per l' Traversable
iterazione, ma questo è l'unico modo per iterare parzialmente quando si usa solo foreach
.
Da un punto di vista, Iterable
è il tratto più impegnativo / potente, poiché puoi facilmente implementare foreach
usando iterator
, ma non puoi davvero implementare iterator
usando foreach
.
In sintesi, Iterable
fornisce un modo per mettere in pausa, riprendere o interrompere l'iterazione tramite un file stateful Iterator
. Con Traversable
, è tutto o niente (senza eccezioni per il controllo del flusso).
Il più delle volte non importa e ti consigliamo l'interfaccia più generale. Ma se hai bisogno di un controllo più personalizzato sull'iterazione, avrai bisogno di un file Iterator
, che puoi recuperare da un file Iterable
.
La risposta di Daniel suona bene. Fammi vedere se riesco a dirlo con parole mie.
Quindi un Iterable può darti un iteratore, che ti consente di attraversare gli elementi uno alla volta (usando next ()) e fermarti e andare come preferisci. Per fare ciò, l'iteratore deve mantenere un "puntatore" interno alla posizione dell'elemento. Ma un Traversable ti dà il metodo, foreach, per attraversare tutti gli elementi contemporaneamente senza fermarti.
Qualcosa come Range (1, 10) deve avere solo 2 interi come stato come Traversable. Ma Range (1, 10) come Iterable ti dà un iteratore che deve usare 3 numeri interi per lo stato, uno dei quali è un indice.
Considerando che Traversable offre anche foldLeft, foldRight, il suo foreach deve attraversare gli elementi in un ordine noto e fisso. Pertanto è possibile implementare un iteratore per un Traversable. Ad esempio def iterator = toList.iterator
Traversable
in Scala 2.13 (è ancora mantenuto come un alias deprecatoIterable
fino al 2.14)