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 (который должен поддерживать этот код после того, как я ухожу) мог выяснить, что делает код и поддерживать его. Они могут даже узнать что-то в процессе.
Ответы
Ответ 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