¿Puedes romper con un maravilloso cierre de "cada"?


¿Es posible break desde un Groovy .each{Closure}, o debería usar un bucle clásico en su lugar?

 129
Author: ArtB, 2010-06-16

6 answers

No, no puedes abortar un "cada uno" sin lanzar una excepción. Es probable que desee un bucle clásico si desea que la interrupción se aborte bajo una condición particular.

Alternativamente, podría usar un cierre "find" en lugar de un each y devolver true cuando hubiera hecho un descanso.

Este ejemplo abortará antes de procesar toda la lista:

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
}

Imprime

1
2
3
4
5

Pero no imprime 6 o 7.

También es muy fácil escribir sus propios métodos iteradores con un comportamiento de ruptura personalizado que acepta cierres:

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
}

También imprime:

1
2
3
4
5    
 175
Author: Ted Naleid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-16 01:48:27

Sustitúyase cada buclepor cualquier cierre.

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

    println element

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

Salida

1
3
 45
Author: Michal Z m u d a,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-07 17:13:46

No, no se puede romper un cierre en Groovy sin lanzar una excepción. Además, no debe usar excepciones para controlar el flujo.

Si te encuentras con ganas de salir de un cierre, probablemente deberías pensar primero en por qué quieres hacer esto y no en cómo hacerlo. Lo primero a considerar podría ser la sustitución del cierre en cuestión por una de las funciones de orden superior (conceptuales) de Groovy. Los siguientes ejemplo:

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

Se convierte en

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

Se convierte en

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

Que también ayuda a la claridad. Establece la intención de su código mucho mejor.

El inconveniente potencial en los ejemplos mostrados es que la iteración solo se detiene al principio del primer ejemplo. Si tiene consideraciones de rendimiento, es posible que desee detenerlo en ese momento.

Sin embargo, para la mayoría de los casos de uso que involucran iteraciones, generalmente puede recurrir a uno de los buscar, grep, recopilar, inyectar, etc. de Groovy. método. Por lo general, toman un poco de "configuración" y luego "saben" cómo hacer la iteración por usted, de modo que pueda evitar el bucle imperativo siempre que sea posible.

 10
Author: Kai Sternad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-17 13:43:13

Solo usando un cierre especial

// 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
}
 2
Author: sea-kg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-04 11:32:32

(1..10).cada{

If (it

Imprimirlo

Else

Devuelve false

 -3
Author: Sagar Mal Shankhala,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-22 06:46:31

Podrías romper por RETURN. Por ejemplo

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

Funciona para mí!

 -8
Author: Tseveen D,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-13 07:38:08