Frage

Es scheint, dass Groovy nicht break und continue aus einem Verschluss unterstützt. Was ist der beste Weg, dies zu simulieren?

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
         // continue to next line...
    }
}
War es hilfreich?

Lösung

können Sie unterstützen nur sauber fortsetzen, nicht zu brechen. Vor allem bei Sachen wie eachLine und jeder. Die Unfähigkeit, Pause zu unterstützen hat damit zu tun, wie diese Methoden ausgewertet werden, gibt es keine Rücksicht genommen für die Schleife nicht Veredelung, die mit dem Verfahren mitgeteilt werden kann. Hier ist, wie weiterhin zu unterstützen -

Bester Ansatz (vorausgesetzt, Sie den resultierenden Wert nicht brauchen).

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
        return // returns from the closure
    }
}

Wenn Sie Ihre Probe wirklich so einfach ist, das ist gut für die Lesbarkeit.

revs.eachLine { line -> 
    if (!(line ==~ /-{28}/)) {
        // do what you would normally do
    }
}

eine weitere Option, was ein simuliert auf einem Bytecode-Ebene normalerweise tun fortsetzen würde.

revs.eachLine { line -> 
    while (true) {
        if (line ==~ /-{28}/) {
            break
        }
        // rest of normal code
        break
    }

}

Eine Möglichkeit Pause zu unterstützen, ist über Ausnahmen:

try {
    revs.eachLine { line -> 
        if (line ==~ /-{28}/) {
            throw new Exception("Break")
        }
    }
} catch (Exception e) { } // just drop the exception

Sie können einen benutzerdefinierten Ausnahmetyp verwenden, um andere wirkliche Ausnahmen zu vermeiden, Maskierung, vor allem, wenn Sie in dieser Klasse eine andere Verarbeitung geht, die wirkliche Ausnahmen auslösen könnte, wie NumberFormatExceptions oder IOExceptions.

Andere Tipps

Verschlüsse können nicht brechen oder fortgesetzt werden, da sie nicht in einer Schleife / Iteration Konstrukte sind. Stattdessen sind sie Werkzeuge zur Verarbeitung / interpretieren / iterative Logik zu behandeln.

: Sie können ohne Verarbeitung durch einfaches Zurück wie in von der Schließung Iterationen gegeben ignore
revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
            return
    }

}

Break Unterstützung passiert bei der Schließung Ebene nicht, sondern wird durch die Semantik des Methodenaufrufes impliziert akzeptierte die Schließung. Kurz gesagt: das heißt, statt „jeder“ auf so etwas wie eine Sammlung von Aufrufen, die die gesamte Kollektion soll verarbeiten Sie anrufen sollten feststellen, welche bis eine bestimmte Bedingung erfüllt ist, verarbeitet. Die meisten (alle?) Mal fühlen Sie die Notwendigkeit, von einem Verschluss zu brechen, was Sie wirklich tun möchte, ist eine bestimmte Bedingung während der Iteration zu finden, die das Spiel find-Methode macht nicht nur Ihre logischen Bedürfnisse, sondern auch Ihre Absicht. Leider fehlt ein Teil der API-Unterstützung für eine Methode find ... Datei zum Beispiel. Es ist möglich, dass die ganze Zeit, ob die Sprache streiten verbrachte Pause umfassen sollte / fortzusetzen, gut angelegt werden konnte, die Methode find diese vernachlässigten Bereiche hinzufügen. So etwas wie firstDirMatching (Closure c) oder findLineMatching (Closure c) würde einen langen Weg gehen und beantworten 99% der „warum kann ich nicht brechen aus ...?“ Fragen, die in den Mailinglisten auftauchen. Das heißt, es ist trivial, diese Methoden selbst über MetaClass oder Kategorien hinzuzufügen.

class FileSupport {
   public static String findLineMatching(File f, Closure c) {
      f.withInputStream {
         def r = new BufferedReader(new InputStreamReader(it))
         for(def l = r.readLine(); null!=l; l = r.readLine())
             if(c.call(l)) return l
         return null
      }
   }
}

using(FileSupport) { new File("/home/me/some.txt").findLineMatching { line ==~ /-{28}/ }

Andere Hacks Ausnahmen und andere Magie beteiligt arbeiten kann aber zusätzlichen Aufwand in einigen Situationen einzuführen und die Lesbarkeit in anderer Konvolut. Die wahre Antwort ist auf dem Code zu suchen und fragen, ob Sie wirklich Iterieren sind oder die Suche statt.

Wenn Sie ein statisches Exception-Objekt in Java vorab erstellen und dann werfen die (statisch) Ausnahme von innen einem Verschluss sind die Laufzeitkosten minimal. Die real Kosten werden bei der Erstellung der Ausnahme entstehen, nicht in sich zu werfen. Laut Martin Odersky (Erfinder von Scala), können viele JVMs tatsächlich throw Anweisungen auf einzelne Sprünge optimieren.

Dies kann dazu verwendet werden, um eine Pause zu simulieren:

final static BREAK = new Exception();
//...
try {
  ... { throw BREAK; }
} catch (Exception ex) { /* ignored */ }

Mit Rückkehr Weiter und jede Schließung brechen .

Beispiel:

Datei-Inhalt:

1
2
----------------------------
3
4
5

Groovy-Code:

new FileReader('myfile.txt').any { line ->
    if (line =~ /-+/)
        return // continue

    println line

    if (line == "3")
        true // break
}

Ausgabe:

1
2
3

In diesem Fall sollten Sie vielleicht denken Sie an der find() Methode. Es stoppt nach dem ersten Mal, wenn der Verschluss an sie übergeben true zurück.

Mit rx-java einer iterable in zu einer beobachtbaren verwandeln kann.

Dann können Sie ersetzen weiter mit einem Filter und brechen mit Takewhile

Hier ist ein Beispiel:

import rx.Observable

Observable.from(1..100000000000000000)
          .filter { it % 2 != 1} 
          .takeWhile { it<10 } 
          .forEach {println it}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top