c'è un modo per "rompere" da una chiusura groovy.è possibile uscire dalla chiusura nel fantastico
forse qualcosa di simile:
[1, 2, 3].each {
println(it)
if (it == 2)
break
}
c'è un modo per "rompere" da una chiusura groovy.è possibile uscire dalla chiusura nel fantastico
forse qualcosa di simile:
[1, 2, 3].each {
println(it)
if (it == 2)
break
}
È possibile generare un'eccezione:
try {
[1, 2, 3].each {
println(it)
if (it == 2)
throw new Exception("return from closure")
}
} catch (Exception e) { }
Usa potrebbe anche usare "findAll" o "grep" per filtrare l'elenco e poi usare "ogni ".
[1, 2, 3].findAll{ it < 3 }.each{ println it }
Dai un'occhiata a Best pattern for simulating continue in groovy closure per un'ampia discussione.
12/05/2013 Molto modificato.
Rispondere alla domanda che è stata posta.
È possibile uscire da una chiusura?
Si potrebbe "rompere" da una chiusura emettendo la parola chiave return
. Tuttavia ciò non è utile nell'esempio fornito. La ragione di ciò è che la chiusura (pensiamo ad essa come un metodo) viene chiamata dal metodo each
per ogni elemento della raccolta.
Se si esegue questo esempio si vedrà che stamperà 1 quindi 3.
[1, 2, 3].each {
if (it == 2) return
println(it)
}
Perché break
nel contesto each
non ha senso.
Per capire perché non è possibile uscire dal metodo each
come si potrebbe uscire da un ciclo for
è necessario capire un po 'di ciò che sta effettivamente accadendo. Ecco una grossolana semplificazione di ciò che fa ogni metodo su una collezione.
myEach([0,1,3])
void myEach(List things) {
for (i in things) {
myEachMethod(i)
}
}
void myEachMethod(Object it) { // this is your Closure
if(it == 2) return
println it
}
Come si può vedere la chiusura è fondamentalmente un metodo che può essere passato in giro. Proprio come in Java non puoi rompere dall'interno della chiamata o chiusura del metodo.
Cosa fare invece di interrompere da each
.
In Groovy si deve esprimere il proprio codice utilizzando astrazioni di alto livello in quanto tale loop primitivo non è idiomatico. Per l'esempio che hai dato, prenderei in considerazione l'idea di findAll. Ad esempio:
[1,2,3].findAll { it < 2 }.each { println it }
Spero che questo ti aiuti a capire cosa sta succedendo.
Risposta alla domanda implicita.
Puoi rompere le iterazioni
Collection.each
rispetto alla chiusura fornita?
Non si può uscire dal metodo each
senza lanciare e rilevare un'eccezione come ha detto John Wagenleitner. Anche se direi che lanciare e catturare un'eccezione nel nome del controllo di flusso è un odore di codice e un collega programmatore potrebbe schiaffeggiare le mani.
Il vostro codice stampa 1, 2, 3 - il ritorno non ritorna da una chiusura. –
Volevo solo chiarire che il ritorno non si "spezzerà" dalla chiusura, restituirà solo il metodo che esegue la chiusura. Nel caso precedente, se ci fosse stata una stampa al di sotto del ritorno, sarebbe stata stampata solo per 1 e 3, tuttavia 1, 2 e 3 sarebbero stati ancora stampati dal primo println. –
Penso che tu sia confuso. "each" è un METODO che accetta una chiusura come argomento. Quindi itera sulla raccolta chiamando la chiusura e passando l'oggetto corrente come argomento alla chiusura. Ho aggiornato la mia risposta per renderlo più chiaro. –
Spesso dimentico che Groovy implementa un metodo "qualsiasi".
[1, 2, 3].any
{
println it
return (it == 2)
}
Questo è a sostegno della risposta di John Wagenleiter. La risposta di Tigerizzy è assolutamente sbagliata. Può essere facilmente smentito praticamente eseguendo il suo primo esempio di codice o teoricamente leggendo la documentazione di Groovy. A restituisce restituisce un valore (o null senza argomento) dall'iterazione corrente, ma non interrompe l'iterazione. In una chiusura si comporta piuttosto come continua.
Non è possibile utilizzare iniettare senza comprenderlo.
Non esiste un modo per "interrompere il ciclo" tranne per l'eccezione. L'utilizzo di eccezioni a questo scopo è considerato maleodorante. Quindi, proprio come suggerisce Wagenleiter, la pratica migliore è quella di filtrare gli elementi che si desidera ripetere prima di avviare ogni o uno dei suoi cugini.
Cercare di utilizzare qualsiasi invece di ogni
def list = [1, 2, 3, 4, 5, -1, -2]
list.any { element ->
if (element > 3)
return true // break
println element
}
Il risultato: 1, 2, 3
Proprio utilizzando speciali Chiusura
// declare and implement:
def eachWithBreak = { list, Closure c ->
boolean bBreak = false
list.each() { it ->
if (bBreak) return
bBreak = c(it)
}
}
def list = [1,2,3,4,5,6]
eachWithBreak list, { it ->
if (it > 3) return true // break 'eachWithBreak'
println it
return false // next it
}
Con rx-java voi può trasformare un iterabile in un obso rvable.
Poi si può sostituire continuano con un filtro di e rottura con TakeWhile
Ecco un esempio:
import rx.Observable
Observable.from(1..100000000000000000)
.filter { it % 2 != 1}
.takeWhile { it<10 }
.forEach {println it}
C'è un altra soluzione. Anche se quella roba groovy come ogni/find/any è piuttosto interessante: se non va bene, non usarla. È ancora possibile utilizzare il vecchio vecchio
for (def element : list)
Soprattutto, se si vuole lasciare il metodo, anche. Ora sei libero di usare continue/break/return come preferisci. Il codice risultante potrebbe non essere bello, ma è facile e comprensibile.
Vorrei andare oltre: utilizzare la soluzione più semplice possibile a meno che non si riesca a vedere una ragione per cui no. Se sei super-fluente in Groovy puoi trovare che usare 'any' qui con' return true' è semplice come questo. Ma il punto di chiusura è che sono progettati per essere passati in giro e manipolati. Per un semplice lavoro, uno strumento semplice e vecchio andrà benissimo! –
Non siete d'accordo che l'utilizzo di Eccezioni per il controllo delle operazioni di flusso è in genere considerato una scelta scadente o un odore di codice? –
Sì. Ma è un modo per uscire dalla chiusura. Naturalmente, di solito ci sono metodi più appropriati come trovare o trovare Tutto. –