Pergunta

Parece que Groovy não suporta break e continue de dentro de um fechamento. Qual é a melhor maneira de simular isso?

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

Solução

Você só pode apoiar continue limpa, não quebrar. Especialmente com coisas como eachLine e cada. A incapacidade de pausa apoio tem a ver com a forma como esses métodos são avaliados, não há nenhuma consideração tomado para não terminar o loop que podem ser comunicadas ao método. Veja como apoiar continuar -

Melhor abordagem (supondo que você não precisa o valor resultante).

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

Se a sua amostra é realmente simples, isso é bom para facilitar a leitura.

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

outra opção, simula o que um continuar faria normalmente em um nível bytecode.

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

}

Uma forma possível de quebra de apoio é através de exceções:

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

Você pode querer usar um tipo de exceção personalizada para evitar mascarar outras exceções reais, especialmente se você tiver outro processamento acontecendo nessa classe que poderia lançar exceções reais, como NumberFormatExceptions ou IOExceptions.

Outras dicas

Closures não pode quebrar ou continuar porque não são LOOP / iteração construções. Em vez disso, são ferramentas utilizadas para efectuar / interpretar / lidar com a lógica iterativa. Você pode ignorar iterações dada pela simples devolução do encerramento sem transformação, como em:

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

}
apoio

Break não acontece ao nível de fechamento, mas sim está implícito a semântica da chamada de método aceitou o fechamento. Em suma, que os meios em vez de chamar "cada" em algo como uma coleção que se destina a processar toda a coleção você deve chamar achado que processará até que uma determinada condição seja atendida. A maioria (todos?) Vezes você sente a necessidade de romper com um fecho que você realmente quer fazer é encontrar uma condição específica durante a sua iteração que torna o método find jogo não só as suas necessidades lógicas, mas também a sua intenção. Infelizmente parte do apoio falta API para um achado método ... arquivo, por exemplo. É possível que todo o tempo gasto discutindo wether a linguagem deve incluir pausa / continue poderia ter sido bem gasto adicionando o método find a essas áreas negligenciadas. Algo como firstDirMatching (Encerramento c) ou findLineMatching (Encerramento c) que percorrer um longo caminho e responder a 99% do "por que não posso quebrar a partir de ...?" questões que surgem nas listas de discussão. Dito isto, é trivial para adicionar esses métodos se via metaclass ou categorias.

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

Outros hacks envolvendo exceções e outras magias podem funcionar, mas introduzir sobrecarga extra em algumas situações e convolute a legibilidade em outros. A verdadeira resposta é olhar para o seu código e perguntar se você está realmente interagindo ou pesquisar em seu lugar.

Se você pré-criar um objeto de exceção estática em Java e, em seguida, lançar a exceção (estático) de dentro de um fechamento, o custo de tempo de execução é mínima. O custo real é incorrido em criar a exceção, não em jogá-lo. De acordo com Martin Odersky (inventor do Scala), muitas JVMs pode realmente otimizar jogar instruções para saltos individuais.

Isto pode ser usado para simular uma pausa:

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

Use retorno para continuar e qualquer fechamento de pausa .

Exemplo

conteúdo do arquivo:

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
}

Output:

1
2
3

Neste caso, você provavelmente deve pensar do método find(). Ele pára após a primeira vez que o encerramento passado para ele retornar true.

Com rx-java você pode transformar um iterável para um observável.

Em seguida, você pode substituir continuar com Filtro e pausa com TakeWhile

Aqui está um exemplo:

import rx.Observable

Observable.from(1..100000000000000000)
          .filter { it % 2 != 1} 
          .takeWhile { it<10 } 
          .forEach {println it}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top