Можете ли вы выйти из Groovy "каждого" закрытия?

Возможно ли break от Groovy .each{Closure}, или я должен использовать классический цикл?

Ответ 1

Нет, вы не можете прервать "каждый", не выбрасывая исключение. Вероятно, вам нужен классический цикл, если вы хотите, чтобы прерывание прерывалось в определенном состоянии.

В качестве альтернативы вы можете использовать закрытие "найти" вместо каждого и вернуть true, если бы вы сделали перерыв.

Этот пример прервется перед обработкой всего списка:

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
}

Печать

1
2
3
4
5

но не печатает 6 или 7.

Также очень легко написать собственные методы итератора с пользовательским поведением break, которые принимают закрытие:

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
}

Также печатает:

1
2
3
4
5    

Ответ 2

Замените цикл each на любую.

def list = [1, 2, 3, 4, 5]
list.any { element ->
    if (element == 2)
        return // continue

    println element

    if (element == 3)
        return true // break
}

Выход

1
3

Ответ 3

Нет, вы не можете выйти из закрытия в Groovy, не вызывая исключения. Кроме того, вы не должны использовать исключения для потока управления.

Если вы обнаружите, что хотите выйти из закрытия, вы должны сначала подумать, почему вы хотите это сделать, а не как это сделать. Первое, что нужно рассмотреть, - это замена рассматриваемого замыкания одной из Groovy (концептуальных) функций более высокого порядка. Следующий пример:

for ( i in 1..10) { if (i < 5) println i; else return}

становится

(1..10).each{if (it < 5) println it}

становится

(1..10).findAll{it < 5}.each{println it} 

что также помогает ясности. В нем говорится о намерении вашего кода намного лучше.

Потенциальный недостаток в приведенных примерах заключается в том, что итерация останавливается только в начале первого примера. Если у вас есть соображения производительности, вы можете остановить его прямо там и там.

Однако для большинства случаев использования, связанных с итерациями, вы обычно можете использовать один из методов Groovy find, grep, collect, inject и т.д. Обычно они берут некоторую "конфигурацию", а затем "знают", как делать итерацию для вас, чтобы вы могли избежать по возможности обязательного цикла.

Ответ 4

Просто используя специальное закрытие

// 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
}

Ответ 5

(1..10).each {

если (it < 5)

println it

еще

return false

Ответ 6

Вы можете сломать RETURN. Например

  def a = [1, 2, 3, 4, 5, 6, 7]
  def ret = 0
  a.each {def n ->
    if (n > 5) {
      ret = n
      return ret
    }
  }

Это работает для меня!