Czy jest możliwe break
z Groovy .each{Closure}
, czy powinienem zamiast tego używać klasycznej pętli?
Czy jest możliwe break
z Groovy .each{Closure}
, czy powinienem zamiast tego używać klasycznej pętli?
Odpowiedzi:
Nie, nie możesz przerwać „każdego” bez rzucenia wyjątku. Prawdopodobnie chcesz klasycznej pętli, jeśli chcesz, aby przerwa została przerwana w określonych warunkach.
Alternatywnie możesz użyć zamknięcia „find” zamiast each i zwrócić prawdę, gdy zrobiłbyś przerwę.
Ten przykład zostanie przerwany przed przetworzeniem całej listy:
def a = [1, 2, 3, 4, 5, 6, 7]
a.find {
if (it > 5) return true // break
println it // do the stuff that you wanted to before break
return false // keep looping
}
Wydruki
1
2
3
4
5
ale nie drukuje 6 lub 7.
Bardzo łatwo jest również napisać własne metody iteratora z niestandardowym zachowaniem przerwania, które akceptuje zamknięcia:
List.metaClass.eachUntilGreaterThanFive = { closure ->
for ( value in delegate ) {
if ( value > 5 ) break
closure(value)
}
}
def a = [1, 2, 3, 4, 5, 6, 7]
a.eachUntilGreaterThanFive {
println it
}
Drukuje również:
1
2
3
4
5
find
lepsze niż any
- zobacz inną odpowiedź poniżej od @Michal, która działa dla mnie
def test = [2] test.findResult{ it * 2 }
zwróci 4 zamiast 2
Wymień każdą pętlę na dowolne zamknięcie.
def list = [1, 2, 3, 4, 5]
list.any { element ->
if (element == 2)
return // continue
println element
if (element == 3)
return true // break
}
Wynik
1
3
any()
w ten sposób jest nieco mylące, ale z pewnością działa i daje możliwość przerwania lub kontynuowania .
Nie, nie możesz zerwać z zamknięciem w Groovy bez rzucenia wyjątku. Nie należy również używać wyjątków dla przepływu sterowania.
Jeśli okaże się, że chcesz wyrwać się z zamknięcia, prawdopodobnie powinieneś najpierw pomyśleć o tym, dlaczego chcesz to zrobić, a nie jak to zrobić. Pierwszą rzeczą do rozważenia może być zastąpienie omawianego zamknięcia jedną z (konceptualnych) funkcji wyższego rzędu Groovy'ego. Poniższy przykład:
for ( i in 1..10) { if (i < 5) println i; else return}
staje się
(1..10).each{if (it < 5) println it}
staje się
(1..10).findAll{it < 5}.each{println it}
co również pomaga uzyskać jasność. Znacznie lepiej określa cel twojego kodu.
Potencjalną wadą pokazanych przykładów jest to, że iteracja zatrzymuje się tylko na początku pierwszego przykładu. Jeśli masz wątpliwości dotyczące wydajności, możesz chcieć zatrzymać to od razu.
Jednak w większości przypadków użycia, które obejmują iteracje, można zwykle skorzystać z jednej z metod Groovy'ego: find, grep, collect, inject itp. Zwykle wymagają pewnej „konfiguracji”, a następnie „wiedzą”, jak wykonać iterację za Ciebie, abyś mógł faktycznie uniknąć bezwzględnego zapętlania się, gdy tylko jest to możliwe.
Używam tylko specjalnego zamknięcia
// 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
}
(1..10) .each {
jeśli (to <5)
wydrukuj to
jeszcze
return false
each
, po prostu nie wypisuje wartości większych niż 4. else
Jest zbędne, twój kod zrobiłby to samo bez niego. Możesz również udowodnić, each
że nie zrywa, return false
jeśli umieścisz println "not breaking"
tuż po else
i tuż przed return false
.
Możesz się przedrzeć RETURN
. Na przykład
def a = [1, 2, 3, 4, 5, 6, 7]
def ret = 0
a.each {def n ->
if (n > 5) {
ret = n
return ret
}
}
Mi to pasuje!
any
metodę tablicy, zwracając false
. Nie możesz złamać each
metody w ten sam sposób.