2009-04-19 4 views
28

Ich möchte von einer Schließung zurückkommen, wie wenn man eine Break-Anweisung in einer Schleife verwendet.Wie kommt man von einer groovigen Schließung zurück und stoppt seine Ausführung?

Zum Beispiel:

largeListOfElements.each{ element-> 
    if(element == specificElement){ 
     // do some work   
     return // but this will only leave this iteration and start the next 
    } 
} 

In dem obigen if-Anweisung würde ich durch die Liste zu stoppen wie Iterieren und lassen Sie den Verschluss unnötige Wiederholungen zu vermeiden.

Ich habe eine Lösung gesehen, bei der eine Ausnahme innerhalb der Schließung geworfen und draußen erwischt wird, aber ich mag diese Lösung nicht allzu gern.

Gibt es andere Lösungen als den Code zu ändern, um diese Art von Algorithmus zu vermeiden?

Antwort

24

Ich denke, Sie wollen suchen statt jeder (zumindest für das angegebene Beispiel). Closures unterstützen den Break nicht direkt.

Unter den Deckeln verwendet groovy eigentlich keinen Verschluss, auch nicht zum Finden, es benutzt eine for-Schleife.

Alternativ können Sie Ihre eigene erweiterte Version von find/jedem Iterator schreiben, die eine bedingte Testschließung durchführt, und eine weitere Schließung, die aufgerufen wird, wenn eine Übereinstimmung gefunden wird.

Hier ist ein Beispiel:

 
Object.metaClass.eachBreak = { ifClosure, workClosure -> 
    for (Iterator iter = delegate.iterator(); iter.hasNext();) { 
     def value = iter.next() 
     if (ifClosure.call(value)) { 
      workClosure.call(value) 
      break 
     }   
    } 
} 

def a = ["foo", "bar", "baz", "qux"] 

a.eachBreak({ it.startsWith("b") }) { 
    println "working on $it" 
} 

// prints "working on bar" 
2

Ich denke, dass Sie auf der falschen Abstraktionsebene arbeiten. Der Block .each macht genau das, was er sagt: Er führt die Schließung einmal für jedes Element aus. Was Sie wahrscheinlich wollen, ist stattdessen List.indexOf zu verwenden, um das richtige specificElement zu finden, und dann die Arbeit zu tun, die Sie darauf tun müssen.

3

Wenn Sie alle Elemente bearbeiten möchten, bis ein spezifisches Sie könnte auch etwas tun, wie dies gefunden:

largeListOfElements.find { element -> 
    // do some work 
    element == specificElement 
} 

Obwohl Sie dies mit jeder verwenden Art von "Break-Zustand". I verwendet nur diese die ersten n Elemente einer Sammlung zu verarbeiten, indem

counter++ >= n 

am Ende des Verschlusses zurückkehrt.

1

Wie ich groovy verstehe, wäre der Weg, diese Art von Schleifen zu schließen, eine benutzerdefinierte Ausnahme zu werfen.Ich weiß nicht, was die Syntax wäre (keine grrovy Programmierer), aber groovy läuft auf der JVM, so wäre es etwas so etwas wie:

class ThisOne extends Exception {Object foo; ThisOne(Object foo) {this.foo=foo;}} 

try { x.each{ if(it.isOk()) throw new ThisOne(it); false} } 
catch(ThisOne x) { print x.foo + " is ok"; }  
1

Nach paulmurray Antwort ich mich nicht sicher, was passieren würde, mit einer Ausnahme aus einem Verschluss geworfen, so peitschte ich einen JUnit Test Case up, das ist leicht zu denken:

class TestCaseForThrowingExceptionFromInsideClosure { 

    @Test 
    void testEearlyReturnViaException() { 
     try { 
      [ 'a', 'b', 'c', 'd' ].each {     
       System.out.println(it) 
       if (it == 'c') { 
        throw new Exception("Found c") 
       } 
      } 
     } 
     catch (Exception exe) { 
      System.out.println(exe.message) 
     } 
    } 
} 

der Ausgang der oben ist:

a 
b 
c 
Found c 

Aber denken Sie daran, dass , siehe insbesondere „sollte man nicht Ausnahmen für die Ablaufsteuerung verwenden“ Um diese Frage Stack-Überlauf: Why not use exceptions as regular flow of control?

So ist die obige Lösung weniger als ideal ist auf jeden Fall. Verwenden Sie einfach:

class TestCaseForThrowingExceptionFromInsideClosure { 

    @Test 
    void testEarlyReturnViaFind() { 
     def curSolution 
     [ 'a', 'b', 'c', 'd' ].find {     
      System.out.println(it) 
      curSolution = it 
      return (it == 'c') // if true is returned, find() stops 
     } 
     System.out.println("Found ${curSolution}") 
    } 
} 

Der Ausgang des oben ist auch:

a 
b 
c 
Found c 
Verwandte Themen