есть ли способ "вырваться" из закрытия groovy.
может быть что-то вроде этого:
[1, 2, 3].each {
println(it)
if (it == 2)
break
}
есть ли способ "вырваться" из закрытия groovy.
может быть что-то вроде этого:
[1, 2, 3].each {
println(it)
if (it == 2)
break
}
Вы можете создать исключение:
try {
[1, 2, 3].each {
println(it)
if (it == 2)
throw new Exception("return from closure")
}
} catch (Exception e) { }
Использование также может использовать "findAll" или "grep" для фильтрации вашего списка, а затем использовать "каждый".
[1, 2, 3].findAll{ it < 3 }.each{ println it }
Я часто забываю, что Groovy реализует "любой" метод.
[1, 2, 3].any
{
println it
return (it == 2)
}
12/05/2013 Тяжело отредактировано.
Отвечая на заданный вопрос.
Можно ли вырваться из закрытия?
Вы можете "вырваться" из закрытия, выпустив ключевое слово return
. Однако это не полезно в приведенном примере. Причиной этого является то, что замыкание (подумайте об этом как методе) вызывается методом each
для каждого элемента в коллекции.
Если вы запустите этот пример, вы увидите, что он будет печатать 1, затем 3.
[1, 2, 3].each {
if (it == 2) return
println(it)
}
Почему break
в контексте each
не имеет смысла.
Чтобы понять, почему вы не можете вырваться из метода each
, как вы могли бы вырваться из цикла for
, вам нужно понять немного того, что на самом деле происходит. Вот грубое упрощение того, что делает каждый метод в коллекции.
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
}
Как вы можете видеть, закрытие - это в основном метод, который можно передать. Как и в java, вы не можете выйти из вызова метода или закрытия.
Что делать, вместо того чтобы ломаться от each
.
В Groovy вы должны выразить свой код, используя абстракции высокого уровня, поскольку такой примитивный цикл не является идиоматическим. Для примера, который вы дали, я бы рассмотрел возможность использования findAll. Например:
[1,2,3].findAll { it < 2 }.each { println it }
Надеюсь, это поможет вам понять, что происходит.
Отвечая на подразумеваемый вопрос.
Вы можете вырваться из итераций
Collection.each
против вашего закрытого закрытия?
Вы не можете вырваться из метода each
, не бросая и не вылавливая исключение, как сказал Джон Вагенлейтнер. Хотя я бы сказал, что бросать и ловить исключение во имя управления потоком - это запах кода, а другой программист может хлопнуть ваши руки.
Взгляните на Лучший образец для моделирования продолжения в закрытии groovy для подробного обсуждения.
Попробуйте использовать любой вместо каждый
def list = [1, 2, 3, 4, 5, -1, -2]
list.any { element ->
if (element > 3)
return true // break
println element
}
Результат: 1, 2, 3
Это в ответ на ответ Джона Вагенлейтера. Ответ Tigerizzy прост. Его можно легко опровергнуть, выполнив первый образец кода или теоретически, прочитав документацию Groovy. Возврат возвращает значение (или значение null без аргумента) из текущей итерации, но не останавливает итерацию. В замыкании он ведет себя как продолжение.
Вы не сможете использовать инъекцию, не понимая этого.
Невозможно "разбить цикл", кроме как выбросить исключение. Использование исключений для этой цели считается вонючим. Итак, как предлагает Wagenleiter, наилучшей практикой является отфильтровать элементы, которые вы хотите перебрать, прежде чем запускать каждого или одного из его кузенов.
Просто используя специальное закрытие
// 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
}
Существует другое решение. Хотя, что groovy материал, как каждый /find/any, довольно крут: если он не подходит, не используйте его. Вы все равно можете использовать простой старый
for (def element : list)
В частности, если вы хотите оставить метод тоже. Теперь вы можете использовать continue/break/return как хотите. Получившийся код может быть не крутым, но это легко и понятно.
С rx-java вы можете преобразовать итерацию в наблюдаемую.
Затем вы можете заменить продолжить фильтр и сломать takeWhile
Вот пример:
import rx.Observable
Observable.from(1..100000000000000000)
.filter { it % 2 != 1}
.takeWhile { it<10 }
.forEach {println it}