web-dev-qa-db-fra.com

Perl Déclenchement d'une déclaration If

Celui-ci vient d'arriver: Comment puis-je sortir d'une déclaration if? J'ai une longue déclaration, mais il y a une situation où je peux m'échapper plus tôt.

En boucle, je peux faire ceci:

while (something ) {
    last if $some_condition;
    blah, blah, blah
    ...
}

Cependant, puis-je faire la même chose avec une déclaration if?

if ( some_condition ) {
    blah, blah, blah
    last if $some_other_condition; # No need to continue...
    blah, blah, blah
    ...
}

Je sais que je pourrais mettre l'instruction if à l'intérieur d'un bloc, puis sortir du bloc:

}
    if ( some_condition ) {
        ...
        last if $some_other_condition; # No need to continue...
        blah, blah, blah
        ...
    }
}

Ou, je peux créer un sous-programme (qui est probablement mieux par programme):

if ( some_condition ) {
    run_subroutine();
}

sub run_subroutine {
    blah, blah, blah
    return if $some_other_condition;
    blah, blah, blah
    ...
}

Mais est-il possible de sortir d'une condition if?


Résolution

La question a été soulevée parce que j'aidais quelqu'un avec son code. Dans une instruction if assez longue, plusieurs autres déclarations if y étaient incorporées. Le code ressemblait à ceci:

 if ( $condition1 ) {
    blah, blah, blah;
    if ( not $condition2 ) {
       blah, blah, blah;
       if ( not $condition3 ) {
          blah, blah, blah;
       }
    }
}

Je pensais que tout pourrait être rendu plus lisible en faisant ceci:

if ( $condition1 ) {
    last if $condition2;
    blah, blah, blah;
    last if $condition3;
    blah, blah, blah;
}

Cela montre que le flux normal de l'instruction if est standard, mais que, dans certaines conditions, l'instruction if a été sortie tôt, ce qui revient à utiliser last ou next dans une boucle while ou for pour la sortir de la boucle.

J'ai aimé la solution de mpapec d'utiliser une étiquette - même si je n'utilise pas l'étiquette elle-même. L’étiquette est une description de ma if:

IF-UNDER-CONDITION1:
{
    if ( $condition1 ) {
        last if $condition2;
        blah, blah, blah;
        last if $condition3;
        blah, blah, blah;
    }
}

Bien que ce ne soit pas une technique de codage standard, le flux de code est suffisamment évident pour qu'un développeur Perl de bas niveau (celui qui doit conserver ce code après mon départ) puisse comprendre ce que le code fait et le conserver. . Ils peuvent même apprendre quelque chose dans le processus.

25
David W.

Vous pouvez utiliser bloc de base qui est sujet à last, next et redo, il y a donc une rupture possible.

if ($condition) {EXIT_IF:{

   last EXIT_IF; # break from code block

   print "never get's executed\n";
}}

EXIT_IF: {
  if ($condition) {

     last EXIT_IF; # break from code block

     print "never get's executed\n";
  }
}
26
Сухой27
  • Placez-le dans une boucle for() vide et ajoutez last; partout où vous souhaitez vous éclater ET après la if. Un peu moche mais ça marche. Assurez-vous d'ajouter des commentaires pour expliquer l'astuce.

    for (;;) {
        if (condition) { 
            #code
            last if another_condition;
        }
        last;
    }
    
  • utilisez goto et étiquetez une instruction après votre boucle pour cela. Être à jamais damné. 

  • Bloc supplémentaire à l'intérieur de la if (par exemple, if () {{ code }}). Peut être difficile à lire pour les novices, mais OK si accompagné d’un commentaire.

  • votre propre solution: bloquer autour de if. Pas très évident en lecture.

  • votre propre solution: sous-programme avec retour. 

    Franchement, à moins que le coût de l’appel d’un sous-chef n’ait plus d’importance, c’est la solution la plus propre en termes de lisibilité}.

3
DVK

Vous pouvez placer le reste de votre bloc if dans une autre instruction if, comme ceci:

if (some_condition) {
    blah, blah, blah
    if (!$some_other_condition) {
        blah, blah, blah
        ...
    }
}
2
Lynn

J'ai tendance à utiliser des instructions if séquentielles basées sur "dois-je continuer?" variable à la place. Votre

if ( $condition1 ) {
  blah, blah, blah;
  if ( not $condition2 ) {
     blah, blah, blah;
     if ( not $condition3 ) {
        blah, blah, blah;
     }
  }
}

peut être réorganisé à

my $ok = $condition1;
if ($ok) {
  blah, blah, blah;
  $ok = not $condition2;
}
if ($ok) {
  blah, blah, blah;
  $ok = not $condition3;
}
if ($ok) {
  blah, blah, blah;
}
0
Louis Strous

La réponse de DVK à jouer m'a inspirée et j'ai proposé cette variante qui fonctionne au moins sur Perl 5.26.1:

for( ; some_condition ; last ) {
    blah, blah, blah
    last if $some_other_condition; # No need to continue...
    blah, blah, blah    
}

Per perlsyn , cela équivaut à:

while (some_condition) {
    blah, blah, blah
    last if $some_other_condition; # No need to continue...
    blah, blah, blah    
} continue {
    last;
}

Dans un bloc continue , last a le même effet que s'il avait été exécuté dans la boucle principale. Par conséquent, la boucle s'exécutera zéro ou une fois, en fonction de some_condition.

Des tests

Perl -E 'my ($cond, $other)=(X, Y); 
         for(;$cond;last) { say "hello"; last if $other; say "goodbye" }'

a les résultats suivants, pour diverses valeurs X et Y:

X Y   Prints
-----------------------
0 0   (nothing)
0 1   (nothing)
1 0   hello, goodbye
1 1   hello
0
cxw

Une autre alternative consiste à utiliser un sous-programme anonyme.
Remarque: Je ne recommande pas cette méthode en raison de la complexité supplémentaire de la portée (voir la remarque ci-dessous); c'est juste pour l'exhaustivité des réponses possibles.

if( $true_condition ){
   (sub{
       return if $true_condition;
       ...
   })->();
}

Remarque: toute variable déclarée avec la routine doit utiliser our au lieu de my si vous souhaitez les utiliser dans le reste du code.

0
vol7ron

Conservez votre boucle while pour pouvoir utiliser last mais aussi en vous assurant que la boucle est exécutée au plus une fois.

my $loop_once = 1;
while ( $loop_once-- and some_condition ) {
    blah, blah, blah
    last if $some_other_condition; # No need to continue...
    blah, blah, blah
    ...
}
0
René Nyffenegger