Meilleur modèle pour simuler & # 8220; continuer & # 8221; en fermeture Groovy

StackOverflow https://stackoverflow.com/questions/205660

  •  03-07-2019
  •  | 
  •  

Question

Il semble que Groovy ne prenne pas en charge break et continue depuis une fermeture. Quelle est la meilleure façon de simuler cela?

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
         // continue to next line...
    }
}
Était-ce utile?

La solution

Vous ne pouvez que continuer à continuer proprement, pas à casser. Surtout avec des trucs comme eachLine et chaques. L’incapacité à prendre en charge la rupture est liée à la manière dont ces méthodes sont évaluées. Il n’est pas tenu compte de la non achèvement de la boucle pouvant être communiquée à la méthode. Voici comment soutenir continuer -

Meilleure approche (en supposant que vous n’avez pas besoin de la valeur résultante).

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

Si votre exemple est aussi simple que cela, il en va de la lisibilité.

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

une autre option simule ce que continuer ferait normalement à un niveau de code intermédiaire.

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

}

Un moyen possible de prendre en charge l'interruption consiste à utiliser des exceptions:

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

Vous voudrez peut-être utiliser un type d'exception personnalisé pour éviter de masquer d'autres exceptions réelles, en particulier si d'autres traitements en cours dans cette classe peuvent générer des exceptions réelles, telles que NumberFormatExceptions ou IOExceptions.

Autres conseils

Les fermetures ne peuvent pas être interrompues ou continuer car elles ne sont pas des constructions en boucle / itération. Ce sont plutôt des outils utilisés pour traiter / interpréter / gérer la logique itérative. Vous pouvez ignorer les itérations données en revenant simplement de la fermeture sans traiter comme dans:

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

}

La prise en charge de la rupture ne se produit pas au niveau de la fermeture mais est plutôt impliquée par la sémantique de l'appel de méthode accepté lors de la fermeture. En bref, cela signifie au lieu d’appeler "chaque". sur quelque chose comme une collection destinée à traiter la totalité de la collection, vous devez appeler find qui traitera jusqu’à ce qu’une certaine condition soit remplie. La plupart (toutes?) Des fois que vous ressentez le besoin de rompre avec une fermeture, ce que vous voulez vraiment faire est de trouver une condition spécifique lors de votre itération, ce qui fait que la méthode de recherche correspond non seulement à vos besoins logiques, mais également à votre intention. Malheureusement, certaines API ne prennent pas en charge une méthode de recherche ... Fichier par exemple. Il est possible que tout le temps passé à débattre pour savoir si le langage devrait inclure la pause / la poursuite aurait bien été passé à ajouter la méthode de recherche à ces zones négligées. Quelque chose comme firstDirMatching (Closure c) ou findLineMatching (Closure c) irait un long chemin et répondrait à 99 +% de la "Pourquoi ne puis-je pas rompre avec ...?" des questions qui apparaissent dans les listes de diffusion. Cela dit, il est facile d’ajouter vous-même ces méthodes via MetaClass ou Catégories.

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

D'autres piratages impliquant des exceptions et d'autres méthodes magiques peuvent fonctionner, mais introduisent des frais généraux supplémentaires dans certaines situations et compliquent la lisibilité dans d'autres. La vraie solution consiste à examiner votre code et à vous demander si vous effectuez une itération ou si vous effectuez une recherche.

Si vous pré-créez un objet Exception statique en Java, puis lancez l'exception (statique) depuis l'intérieur d'une fermeture, le coût d'exécution est minimal. Le coût réel est lié à la création de l'exception et non à son lancement. Selon Martin Odersky (inventeur de Scala), de nombreuses machines virtuelles peuvent optimiser les instructions de lancer en sauts simples.

Ceci peut être utilisé pour simuler une pause:

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

Utilisez return pour continuer et une clôture pour rompre .

Exemple

Contenu du fichier:

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

Code Groovy:

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

    println line

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

Sortie:

1
2
3

Dans ce cas, vous devriez probablement penser à la méthode find () . Il s'arrête après la première fois que la fermeture lui a été renvoyée, retourne à true.

Avec rx-java , vous pouvez transformer un élément itérable en un élément observable.

Ensuite, vous pouvez remplacer continuer par un filtre et une pause par takeWhile

.

Voici un exemple:

import rx.Observable

Observable.from(1..100000000000000000)
          .filter { it % 2 != 1} 
          .takeWhile { it<10 } 
          .forEach {println it}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top