Подтвердить что ты не робот

Perl Нарушение оператора If

Это только что пришло в голову: как мне выйти из заявления if? У меня длинное выражение if, но есть одна ситуация, когда я могу выйти из него на раннем этапе.

В цикле я могу сделать это:

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

Однако могу ли я сделать то же самое с оператором if?

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

Я знаю, что могу поместить оператор if в блок, а затем я могу выйти из блока:

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

Или я могу создать подпрограмму (что, вероятно, лучше программно):

if ( some_condition ) {
    run_subroutine();
}

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

Но есть ли способ выйти из условия if?


Разрешение

Вопрос возник, потому что я помогал кому-то с их кодом. Внутри довольно длинного оператора if в него было встроено несколько других операторов if. Код выглядел примерно так:

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

Я думал, что все это можно сделать более читабельным, сделав это:

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

Это показывает, что нормальный поток оператора if является стандартным, но при определенных условиях оператор if был завершен досрочно - очень похоже на использование last или next в while или for цикл для выхода из цикла.

Мне понравилось mpapec решение использовать ярлык - даже если я не использую сам ярлык. Этикетка является описанием моего if:

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

Хотя это не стандартная методика кодирования, поток кода достаточно очевиден, чтобы типичный низкоуровневый разработчик Perl (который должен поддерживать этот код после того, как я ухожу) мог выяснить, что делает код и поддерживать его. Они могут даже узнать что-то в процессе.

4b9b3361

Ответ 1

Вы можете использовать базовый блок, который подпадает под last, next и redo, поэтому существует возможный разрыв с ним.

if ($condition) {EXIT_IF:{

   last EXIT_IF; # break from code block

   print "never get executed\n";
}}

EXIT_IF: {
  if ($condition) {

     last EXIT_IF; # break from code block

     print "never get executed\n";
  }
}

Ответ 2

  • Поместите его в пустой цикл for() и добавьте last; всюду, где вы хотите вырваться И после if. Немного уродливый, но работает. Не забудьте добавить комментарии, чтобы объяснить трюк.

    for (;;) {
        if (condition) { 
            #code
            last if another_condition;
        }
        last;
    }
    
  • используйте goto и помечайте инструкцию после своего цикла для этого goto. Будьте навеки прокляты.

  • Дополнительный блок внутри if (например, if () {{ code }}). Может быть трудно читать для новичков, но ОК, если они сопровождаются комментарием.

  • ваше собственное решение: заблокировать if. Не очень очевидная читаемость.

  • ваше собственное решение: подпрограмма с возвратом.

    Честно говоря, если стоимость вызова вспомогательных вопросов не выполняется, это самое чистое решение в отношении удобочитаемости.

Ответ 3

Вы можете разместить оставшуюся часть вашего блока if внутри другого оператора if, например:

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

Ответ 4

Другой альтернативой является использование анонимной подпрограммы. Примечание.. Я не рекомендую этот метод из-за сложной сложности охвата (см. примечание ниже); это просто для полноты возможных ответов.

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

Примечание. любые переменные, объявленные w/в подпрограмме, должны использовать our вместо my, если вы хотите использовать их в остальной части кода.

Ответ 5

Я предпочитаю использовать последовательные if-утверждения, основанные на "продолжить?". вместо переменной. Ваш

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

можно переставить на

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

Ответ 6

Сохраните цикл while, чтобы вы могли использовать last, но также убедитесь, что цикл выполняется не более одного раза

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

Ответ 7

Я был вдохновлен ответом DVK, чтобы поиграть, и я придумал этот вариант, который работает по крайней мере на Perl 5.26.1:

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

На perlsyn это эквивалентно:

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

В блоке continue last действует так же, как если бы он был выполнен в основном цикле. Поэтому цикл будет выполняться ноль или один раз, в зависимости от some_condition.

тесты

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

имеет следующие результаты для различных значений X и Y:

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