67 votos

Mejor patrón para la simulación de "continuar" en Groovy cierre

Parece que Groovy no admite pausa y continuar desde dentro de un cierre. ¿Cuál es la mejor manera de simular esto?

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
            // continue to next line...
    }

}

71voto

shemnon Puntos 2685

Usted sólo puede apoyar continuar limpiamente, no se rompa. Sobre todo con cosas como eachLine y cada uno de ellos. La incapacidad para soportar la ruptura tiene que ver con la forma en que esos métodos son evaluados, no hay ninguna consideración para no terminar el bucle que puede ser comunicada al método. He aquí cómo apoyar a continuar --

Mejor enfoque (suponiendo que usted no necesita el valor resultante).

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
        return // returns from the closure
    }
}

Si la muestra es realmente simple, esto es bueno para mejorar la legibilidad.

revs.eachLine { line -> 
    if (!(line ==~ /-{28}/)) {
        // do what you would normally do
    }
}

otra opción, simula qué continuar haría normalmente en un bytecode nivel.

revs.eachLine { line -> 
    while (true) {
        if (line ==~ /-{28}/) {
            break
        }
        // rest of normal code
        break
    }

}

Una posible manera de apoyar a romper es a través de excepciones:

try {
    revs.eachLine { line -> 
        if (line ==~ /-{28}/) {
            throw new Exception("Break")
        }
    }
} catch (Exception e) { } // just drop the exception

Puede que quieras usar un tipo de excepción para evitar enmascarar otras excepciones reales, especialmente si usted tiene otros procesos de transformación que está ocurriendo en la clase que podrían lanzar excepciones reales, como NumberFormatExceptions o IOExceptions.

15voto

Cliff Puntos 3598

Los cierres pueden romper o continuar porque no son de bucle/iteración construcciones. En lugar de que son herramientas que se utilizan para procesar/interpretar/identificador de proceso iterativo de la lógica. Usted puede ignorar dado de iteraciones por simplemente regresar desde el cierre sin procesar como en:

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
            return
    }

}

Salto de apoyo no sucede en el cierre de nivel sino que está implícita en la semántica de la llamada al método aceptado el cierre. En definitiva esto significa que en lugar de llamar a "cada uno" en algo parecido a una colección que está pensado para procesar toda la colección debe llamar a encontrar que el proceso hasta que se cumpla cierta condición. La mayoría (todos?) veces se siente la necesidad de alejarse de un cierre de lo que realmente quieres hacer es encontrar una condición específica durante la iteración que hace que el método de búsqueda de coincidir no sólo su lógica necesidades, sino también su intención. Lamentablemente algunas de las API falta de apoyo para un método de búsqueda... de Archivo, por ejemplo. Es posible que todo el tiempo dedicado argumentando que si el lenguaje debe incluir pausa/continuar podría haber sido bien gastado añadir el método find para estas zonas abandonadas. Algo así como firstDirMatching(Cierre c) o findLineMatching(Cierre c) iría un largo camino y la respuesta del 99% de los "¿por qué no puedo romper...?" las preguntas que aparecen en las listas de correo. Dicho esto, es trivial para agregar estos métodos de sí 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 hacks que implican las excepciones y otros magia puede funcionar, pero introducir sobrecarga adicional en algunas situaciones y contortos la legibilidad en los demás. La verdadera respuesta es mirar el código y pregunte si usted está verdaderamente recorrer o buscar en su lugar.

10voto

Ralph Puntos 9405

Si antes de crear una estática objeto de Excepción en Java y, a continuación, tirar de la (estática) de excepción desde el interior de un cierre, el tiempo de ejecución costo es mínimo. Es el costo real incurrido en la creación de la excepción, no en tirar. Según Martin Odersky (inventor de la Scala), muchos Jvm puede optimizar tirar instrucciones a solo salta.

Esto puede ser usado para simular un descanso:

final static BREAK = new Exception();
//...
try {
  ... { throw BREAK; }
} catch (Exception ex) { /* ignored */ }

8voto

Michal Zmuda Puntos 716

El uso de retorno para continuar y cualquier cierre a romper.

Ejemplo

Contenido del archivo:

1
2
----------------------------
3
4
5

Groovy código:

new FileReader('myfile.txt').any { line ->
    if (line =~ /-+/)
        return // continue

    println line

    if (line == "3")
        true // break
}

Salida:

1
2
3

3voto

0rt Puntos 31

En este caso, usted probablemente debería pensar en la find() método. Se detiene después de la primera vez que el cierre se pasan a devolver true.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X