czy istnieje sposób na "zerwanie" z groovy zamknięcia.czy możliwe jest wyrwanie się z zamknięcia w groovy
może coś takiego:
[1, 2, 3].each {
println(it)
if (it == 2)
break
}
czy istnieje sposób na "zerwanie" z groovy zamknięcia.czy możliwe jest wyrwanie się z zamknięcia w groovy
może coś takiego:
[1, 2, 3].each {
println(it)
if (it == 2)
break
}
Można wyjątek:
try {
[1, 2, 3].each {
println(it)
if (it == 2)
throw new Exception("return from closure")
}
} catch (Exception e) { }
użycie może również użyć „FindAll” lub „grep” odfiltrować listę, a następnie użyć „każdy ".
[1, 2, 3].findAll{ it < 3 }.each{ println it }
Spójrz na Best pattern for simulating continue in groovy closure dla szerokiej dyskusji.
12/05/2013 Mocno edytowane.
Odpowiedzi na pytanie, które zadano.
Czy możliwe jest wyjście z zamknięcia?
można byłoby "break" Spośród zamknięcia wydając słowa kluczowego return
. Jednak nie jest to pomocne w podanym przykładzie. Powodem tego jest to, że zamknięcie (myśl o nim jako metodzie) jest wywoływane przez metodę each
dla każdego elementu w kolekcji.
Jeżeli Państwo uruchomić ten przykład widać to wydrukować 1 to 3.
[1, 2, 3].each {
if (it == 2) return
println(it)
}
Dlaczego break
w kontekście each
nie ma sensu.
Aby zrozumieć, dlaczego nie można wykluczyć metody each
, tak jakbyś mógł zerwać z pętli for
, musisz zrozumieć trochę tego, co się naprawdę dzieje. Oto ogromne uproszczenie, jakie ma każda metoda w kolekcji.
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
}
Jak widać zamknięcie jest w zasadzie metodą, którą można przekazać. Podobnie jak w Javie, nie można oderwać się od wywołania metody lub zamknięcia.
Co zrobić zamiast zerwania z each
.
W Groovy powinieneś wyrażać swój kod używając abstrakcji wysokiego poziomu, ponieważ taka prymitywna pętla nie jest idiomatyczna. Na przykład, który podałeś rozważałbym skorzystanie z findAll. Na przykład:
[1,2,3].findAll { it < 2 }.each { println it }
Mam nadzieję, że pomoże to zrozumieć, co się dzieje.
Odpowiedzi na domniemane pytanie.
Czy można zerwać z iteracji
Collection.each
przeciwko dostarczonego zamknięcia?
Nie można wykluczyć metody each
bez rzucania i łapania wyjątków, jak powiedział John Wagenleitner. Chociaż twierdzę, że rzucanie i łapanie wyjątków w imię kontroli przepływu jest zapachem kodu, a inny programista może uderzyć cię w dłonie.
Twój kod drukuje 1, 2, 3 - powrót nie powróci z zamknięcia. –
Chciałem tylko wyjaśnić, że powrót nie "wyrwie się" z zamknięcia, po prostu zwróci metodę wykonującą zamknięcie. W powyższym przypadku, gdyby był wydruk poniżej zwrotu, wydrukowałby on tylko 1 i 3, jednak 1, 2 i 3 nadal były drukowane przez pierwszy println. –
Myślę, że jesteś zdezorientowany. "każdy" jest METODĄ, która przyjmuje argument jako zamknięcie. Następnie wykonuje iterację nad zbiorem wywołującym zamknięcie i przekazując bieżący obiekt jako argument do zamknięcia. Zaktualizowałem moją odpowiedź, aby było to bardziej jasne. –
Często zapominam, że Groovy stosuje metodę "any".
[1, 2, 3].any
{
println it
return (it == 2)
}
Jest to poparcie dla odpowiedzi Johna Wagenleitera. Odpowiedź Tigerizzy'ego jest całkiem błędna. Z łatwością można go praktycznie obalić, wykonując swoją pierwszą próbkę kodu lub teoretycznie czytając dokumentację Groovy. A return zwraca wartość (lub wartość zerową bez argumentu) z bieżącej iteracji, ale nie zatrzymuje iteracji. W zamknięciu zachowuje się raczej jak kontynuuje.
Nie będziesz w stanie użyć wstrzyknięcia bez zrozumienia.
Nie ma sposobu, aby "przerwać pętlę", z wyjątkiem sytuacji, gdy wystąpi wyjątek. Używanie wyjątków w tym celu jest uważane za śmierdzące. Tak więc, jak sugeruje Wagenleiter, najlepszą praktyką jest odfiltrowanie elementów, które chcesz powtórzyć przed uruchomieniem każdego lub jednego z kuzynów.
spróbuje użyć dowolny zamiast każdy
def list = [1, 2, 3, 4, 5, -1, -2]
list.any { element ->
if (element > 3)
return true // break
println element
}
Rezultat: 1, 2, 3
tylko za pomocą specjalnego Zamknięcie
// 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
}
Z rx-java ty może przekształcić wartość iterowalną w obsesję RVable.
Następnie można zastąpić kontynuować z filtra i przerwie z takeWhile
Oto przykład:
import rx.Observable
Observable.from(1..100000000000000000)
.filter { it % 2 != 1}
.takeWhile { it<10 }
.forEach {println it}
Jest inne rozwiązanie. Chociaż te fajne rzeczy, takie jak each/find/any, są całkiem fajne: jeśli to nie pasuje, nie używaj tego. Nadal można jednak używać zwykłego starego, zwykłego, Teraz możesz swobodnie używać kontynuacji/break/return, jak chcesz. Wynikowy kod może nie być cool, ale jest łatwy i zrozumiały.
Poszedłbym dalej: użyj najprostszego możliwego rozwiązania, chyba że widzisz powód, dlaczego nie. Jeśli jesteś super-biegły w Groovy, możesz użyć 'jakiegokolwiek' tutaj z 'return true' by być tak prostym jak ten. Ale zamknięcia są takie, że są zaprojektowane tak, aby można je było ominąć i manipulować nimi. W przypadku zwykłej pracy proste narzędzie będzie dobrze działać! –
Czy nie zgodziłbyś się, że używanie wyjątków do sterowania przepływem jest zwykle uważane za zły wybór lub zapach kodu? –
Tak. Ale jest to sposób na wyjście z zamknięcia. Oczywiście zwykle istnieją bardziej odpowiednie metody, takie jak znajdowanie lub znajdowanie wszystkiego. –