Можете ли вы оторваться от Groovy "каждый" замыкание? - PullRequest
140 голосов
/ 16 июня 2010

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

Ответы [ 6 ]

184 голосов
/ 16 июня 2010

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

В качестве альтернативы, вы могли бы использовать замыкание «найти» вместо каждого и возвращать 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.

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

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    
51 голосов
/ 17 октября 2013

Заменить каждый цикл на любое замыкание.

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
10 голосов
/ 17 июня 2010

Нет, вы не можете выйти из замыкания в 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: поиск, grep, collect, inject и т. Д.,Они обычно принимают некоторую «конфигурацию», а затем «знают», как выполнить итерацию за вас, чтобы вы могли избежать императивного зацикливания, где это возможно.

2 голосов
/ 04 марта 2014

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

// 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
}
0 голосов
/ 22 мая 2016

(1..10) .each {

если (это <5) </p>

распечатать

еще

вернуть false

0 голосов
/ 01 августа 2011

Вы можете разбить на RETURN. Например

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

У меня работает!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...