2010-04-08 11 views
16

So che per essere Traversable, è necessario solo un metodo foreach. Iterable richiede un metodo iterator.Nelle raccolte di Scala 2.8, perché il tipo Traversable è stato aggiunto sopra Iterable?

Sia il SID delle raccolte di Scala 2.8 che il documento "Fighting Bitrot with Types" sono sostanzialmente in silenzio sul motivo del perché è stato aggiunto Traversable. Il SID dice solo "David McIver ... ha proposto Traversable come generalizzazione di Iterable".

Ho vagamente raccolto dalle discussioni su IRC che ha a che fare con il recupero delle risorse quando l'attraversamento di una raccolta termina?

Quanto segue è probabilmente correlato alla mia domanda. Ci sono alcune definizioni di funzioni dispari cercando in TraversableLike.scala, ad esempio:

def isEmpty: Boolean = { 
    var result = true 
    breakable { 
    for (x <- this) { 
     result = false 
     break 
    } 
    } 
    result 
} 

Presumo ci sia una buona ragione che non è stato appena scritto come:

def isEmpty: Boolean = { 
    for (x <- this) 
    return false 
    true 
} 
+0

'Traversable' è motivato in Ch. 24 di Programmazione in Scala, 2a ed .; in alcuni casi è più facile implementare in modo efficiente 'foreach' di' iterator'. – Blaisorblade

+0

Per quanto riguarda l'ultima domanda: https://github.com/scala/scala/pull/5101 – floating

risposta

3

Ho il sospetto che uno dei motivi è che si tratta di un molto più facile scrivere un'implementazione concreta per una raccolta con un metodo astratto foreach rispetto a uno con un metodo astratto iterator. Ad esempio, in C# è possibile scrivere l'applicazione del metodo di IEnumerable<T>GetEnumerator come se si trattasse di un metodo foreach:

IEnumerator<T> GetEnumerator() 
{ 
    yield return t1; 
    yield return t2; 
    yield return t3; 
} 

(. Il compilatore genera una macchina di stato appropriato per guidare l'iterazione attraverso l'IEnumerator) In Scala, dovresti scrivere la tua implementazione di Iterator[T] per farlo. Per Traversable, si può fare l'equivalente di quanto sopra implementazione:

def foreach[U](f: A => U): Unit = { 
    f(t1); f(t2); f(t3) 
} 
+0

Sono abbastanza nuovo su scala, ma dal momento che in realtà non si restituisce nulla, non potresti scrivere 'def foreach [U ] (f: A => U) {f (t1); f (t2); f (t3)} '? – tstenner

+0

'foreach' afferma che restituisce' Unit' e quindi scarta il risultato del body block 'f (t3)' di tipo 'U'. –

9

ho chiesto a David McIver su questo su IRC. Ha detto che non ricordava più tutte le ragioni, ma hanno incluso:

  • "iteratori sono spesso fastidioso ... per implementare"

  • iteratori sono "a volte non sicuro (a causa di setup/teardown a l'inizio e la fine del ciclo)"

  • auspicato aumento dell'efficienza derivante attuazione di alcune cose tramite foreach anziché mediante iteratori (utili non necessariamente ancora effettivamente dimostrato con il compilatore HotSpot corrente)

-3

solo per quanto riguarda la tua ultima domanda:

def isEmpty: Boolean = { 
    for (x <- this) 
    return false 
    true 
} 

Questo viene tradotto approssimativamente dal compilatore per:

def isEmpty: Boolean = { 
    this.foreach(x => return false) 
    true 
} 

Quindi non sono semplicemente in grado di uscire da foreach, isEmpty restituirà sempre vero .

Questo è il motivo per cui è stato creato "hacky" Breakable che esce da foreach generando un'eccezione di controllo, rilevandola in breakable e restituisce.

+3

In realtà ti sbagli sul ritorno in scala. Scala supporta i resi non locali. – Eastsun

+0

Eastsun ha ragione, come si può facilmente verificare nel repl. –

+0

Uh, questo è sorprendente, hai ragione. È sempre stato valido ?? – hotzen

Problemi correlati