2016-08-04 30 views
1

Dieser Code gibt true zurück, wie erwartet:Wie aufrufen TraversableLike.exists meine benutzerdefinierten Sammlungen foreach

class MyList extends Traversable[Int] { 
    def foreach[U](f: Int => U) = { 
    f(1) 
    f(2) 
    f(3) 
    } 
} 
object Test extends App { 
    println(new MyList().exists(_ == 2)) 
} 

MyList braucht nur foreach zu definieren, um eine Traversable zu implementieren. Also, irgendwo die exists Funktion ruft MyList.foreach. Einen Haltepunkt bei f(1) setzend, sehe ich, dass foreach durch TraversableLike Linie 352 for (x <- this) genannt wird. Also, ist x <- this Aufruf foreach? Wie? Ich sehe den Anruf an foreach nirgendwo.

349: def exists(p: A => Boolean): Boolean = { 
    350: var result = false 
    351: breakable { 
    352:  for (x <- this) 
    353:  if (p(x)) { result = true; break } 
    354: } 
    355: result 
    366: } 
+0

Es ist 'für' das' foreach' nennt, denke ich. –

+1

Ja, alle "for" -Komprimierungen werden vom Compiler in 'map',' flatMap' und 'foreach' (was immer benötigt wird) umgeschrieben. – jwvh

+2

Siehe http://stackoverflow.com/questions/9891407/getting-the-desugared-part-of-a-scala-for-comprehension-expression – mfirry

Antwort

1

Die Scala-Spezifikation in Bezug auf For Comprehension and For Loops spricht über dies genau:

Die genaue Bedeutung von Generatoren und Wachen durch Übersetzung zu Anrufungen von vier Methoden definiert: map, withFilter, flatMap und foreach. Diese Methoden können auf verschiedene Arten für verschiedene Trägertypen implementiert werden.

So ist die Übersetzung effektiv:

def exists(p: A => Boolean): Boolean = { 
    var result = false 
    breakable { 
    this.foreach(x => if (p(x)) { result = true; break }) 
    } 
    result 
} 

Und das ist, warum Sie Ihre foreach wird aufgerufen sehen.

Für verschiedene Zwecke können Sie verschiedene Übersetzungen sehen, die alle in der Spezifikation angegeben sind.

1

Yuval ist korrekt. Aber im Allgemeinen finde ich, dass die Bezugnahme auf den Link, den er gibt, etwas ermüdend wird. Besonders wenn ich tief in einer for Schleife bin verstehe ich nicht.

Ich habe ein Makro entwickelt, mit dem ich herausfinden kann, wie die Dinge entkernt werden. Es ist ziemlich praktisch und funktioniert von der scala REPL. Öffnen Sie einfach eine Sitzung, und fügen Sie ihn in

import scala.language.experimental.macros 
import scala.reflect.macros.blackbox.Context 

// inspect how scala has desugared your code 
def traceSugar[T](t: T): T = macro impl 
def impl(c: Context)(t: c.Tree): c.Tree = { println(t); t } 

Dann, wenn Sie jemals sehen wollen, wie etwas de-Zucker, nur wickeln Sie es in traceSugar. Es wird die entzuckerte Version drucken und den Ausdruck bewerten. Sehr praktisch für die haarigen for Loops. In Ihrem Fall

scala> traceSugar { 
| var result = false 
| breakable { 
|  for (x <- Seq(1,2,3)) 
|  if (x > 1) { result = true; break } 
| } 
| result 
| } 

Ergebnisse in

{ 
    var result: Boolean = false; 
    scala.util.control.Breaks.breakable(collection.this.Seq.apply[Int](1, 2, 3).foreach[Unit](((x: Int) => if (x.>(1)) 
    { 
     result = true; 
     scala.util.control.Breaks.break() 
    } 
    else 
    ()))); 
    result 
} 
res8: Boolean = true 

Sie sehen die foreach, sowie wie breakable funktioniert.