variable - groovy when then
El mejor patrĂ³n para simular "continuar" en el cierre de Groovy (6)
Con rx-java puede transformar un iterable en un observable.
Luego puede reemplazar continuar con un filtro y romper con takeWhile
Aquí hay un ejemplo:
import rx.Observable
Observable.from(1..100000000000000000)
.filter { it % 2 != 1}
.takeWhile { it<10 }
.forEach {println it}
Parece que Groovy no admite break
y continue
desde dentro de un cierre. ¿Cuál es la mejor manera de simular esto?
revs.eachLine { line ->
if (line ==~ /-{28}/) {
// continue to next line...
}
}
En este caso, probablemente deberías pensar en el método find()
. Se detiene después de la primera vez que el cierre pasó a ser verdadero.
Los cierres no pueden romperse o continuar porque no son constructos de bucle / iteración. En su lugar, son herramientas utilizadas para procesar / interpretar / manejar la lógica iterativa. Puede ignorar las iteraciones dadas simplemente volviendo del cierre sin procesar como en:
revs.eachLine { line ->
if (line ==~ /-{28}/) {
return
}
}
El soporte de ruptura no ocurre en el nivel de cierre, sino que está implícito en la semántica del método, la llamada acepta el cierre. En resumen, eso significa que en lugar de llamar a "cada uno" sobre algo así como una colección que pretende procesar toda la colección, debe llamar a find para que procese hasta que se cumpla una determinada condición. La mayoría de las veces (¿todas?) En las que siente la necesidad de abandonar un cierre lo que realmente quiere hacer es encontrar una condición específica durante la iteración, lo que hace que el método de búsqueda no solo coincida con sus necesidades lógicas sino también con su intención. Lamentablemente, algunas de las API carecen de soporte para un método de búsqueda ... Archivo, por ejemplo. Es posible que todo el tiempo pasado argumentando si el lenguaje debería incluir break / continue podría haber sido bien empleado agregando el método de búsqueda a estas áreas descuidadas. Algo así como firstDirMatching (Closure c) o findLineMatching (Closure c) sería muy útil y respondería al 99 +% de "¿por qué no puedo separarme de ...?" preguntas que aparecen en las listas de correo. Dicho esto, es trivial agregar estos métodos usted mismo a través de MetaClass o Categorías.
class FileSupport {
public static String findLineMatching(File f, Closure c) {
f.withInputStream {
def r = new BufferedReader(new InputStreamReader(it))
for(def l = r.readLine(); null!=l; l = r.readLine())
if(c.call(l)) return l
return null
}
}
}
using(FileSupport) { new File("/home/me/some.txt").findLineMatching { line ==~ /-{28}/ }
Otros ataques que implican excepciones y otra magia pueden funcionar, pero introducen sobrecarga adicional en algunas situaciones y complican la legibilidad en otras. La verdadera respuesta es mirar su código y preguntar si realmente está iterando o buscando en su lugar.
Si pre-crea un objeto Exception estático en Java y luego lanza la excepción (estática) desde el interior de un cierre, el costo de tiempo de ejecución es mínimo. El costo real se incurre al crear la excepción, no al tirarla. Según Martin Odersky (inventor de Scala), muchas JVM en realidad pueden optimizar las instrucciones de lanzamiento para saltos individuales.
Esto se puede usar para simular un descanso:
final static BREAK = new Exception();
//...
try {
... { throw BREAK; }
} catch (Exception ex) { /* ignored */ }
Solo puedes soportar continuar limpiamente, no romper. Especialmente con cosas como EachLine y cada uno. La incapacidad para soportar la interrupción tiene que ver con la forma en que se evalúan esos métodos, no se tiene en cuenta la finalización del ciclo que se puede comunicar al método. He aquí cómo apoyar continuar -
El mejor enfoque (suponiendo que no necesita el valor resultante).
revs.eachLine { line ->
if (line ==~ /-{28}/) {
return // returns from the closure
}
}
Si su muestra es así de simple, esto es bueno para la legibilidad.
revs.eachLine { line ->
if (!(line ==~ /-{28}/)) {
// do what you would normally do
}
}
otra opción, simula lo que normalmente haría una continuación en un nivel de código de bytes.
revs.eachLine { line ->
while (true) {
if (line ==~ /-{28}/) {
break
}
// rest of normal code
break
}
}
Una forma posible de apoyar la ruptura es a través de excepciones:
try {
revs.eachLine { line ->
if (line ==~ /-{28}/) {
throw new Exception("Break")
}
}
} catch (Exception e) { } // just drop the exception
Es posible que desee utilizar un tipo de excepción personalizado para evitar enmascarar otras excepciones reales, especialmente si tiene en curso otro procesamiento en esa clase que podría arrojar excepciones reales, como NumberFormatExceptions o IOExceptions.
Use return para continuar y cualquier cierre para romper .
Ejemplo
Contenido del archivo:
1
2
----------------------------
3
4
5
Código Groovy:
new FileReader(''myfile.txt'').any { line ->
if (line =~ /-+/)
return // continue
println line
if (line == "3")
true // break
}
Salida:
1
2
3