Следует ли избегать вложенных операторов if в Perl?
Я делаю некоторые Perl и вижу, что мои вложенные утверждения "if" сводят меня с ума. Мне удалось уменьшить некоторые из них с помощью защитных блоков в другой секции, но я застрял здесь.
Как вы думаете, я могу оставить код как есть, или есть "правильный" способ рефакторинга следующего ? (Я также признаю, что относительно новичок в Perl)
это фактически подпрограмма, запрашивающая ввод пользователя для каждого параметра списка (внешнего файла). $[3] - соответствующий шаблон, $[2] является значением по умолчанию для рассматриваемого параметра (NULL, если нет), $_[1] указывает, является ли он обязательным или нет. оператор 'next' ссылается на следующий параметр read (while loop).
С каждого (спасибо !), вот новейшая версия.
100 if ( $input ne '' && ( $input !~ $match || $input =~ /'.+'/ ) ) {
101 print "! Format not respected. Match : /$match/ (without ' ')n";
102 next;
103 }
104 if ( $input eq '' ) {
105 if ( $default eq 'NULL' ) {
106 if ( $manda eq 'y' ) {
107 print "! Mandatory parameter not filled inn";
108 next;
109 }
110 print "+ Ignoring parameter.n";
111 $input = '';
112 }
113 else {
114 print "+ Using default valuen";
115 $input = $default;
116 }
117 }
98 if($input eq ''){
99 if($_[2] eq 'NULL'){
100 if($_[1] eq 'y'){
101 print "! Mandatory parameter not filled inn";
102 next;
103 }
104 else{
105 print "+ Ignoring parameter.n";
106 $input = '';
107 }
108 }
109 else{
110 print "+ Using default valuen";
111 $input = $_[2];
112 }
113 }
114 elsif($input !~ $_[3] || $input =~ /'.+'/){
115 print "! Format not respected. Match : /$_[3]/ (without ' ')n";
116 next;
117 }
118 }
10 ответов
вот немного более читаемая версия chaos ' answer:
# Set sane variable names...
my ($is_required, $default, $pattern) = @_
# Convert the external string convention for simpler evaluation...
$default = undef if $default eq 'NULL'
# Refuse problematic input before going any further...
if ($input ne '' && $input !~ $pattern || $input =~ /'.+'/) {
print "! Format not respected. Match : /$pattern/ (without \' \')\n";
next;
}
# If there was no input string...
if($input eq '') {
# Set the default, if one was provided...
if( $default ) {
print "+ Using default value\n";
$input = $default;
}
# otherwise, complain if a default was required...
else {
if( $is_required eq 'y' ){
print "! Mandatory parameter not filled in\n";
next;
}
print "+ Ignoring parameter (no input or default provided).\n";
}
}
ключевые требования:
- не нужно другое если вы выходите из текущего цикла с далее
- исключительные случаи должны быть обработаны в первую очередь
- вы можете значительно улучшить читаемость, используя именованные переменные
альтернативный подход, который иногда помогает с удобочитаемостью, заключается в том, чтобы поместить некоторые или все ветви в хорошо названные ссылки на код. Вот начало идеи:
$format_not_respected = sub {
return 0 if ...;
print "! Format not respected....";
return 1;
}
$missing_mandatory_param = sub {
return 0 if ...;
print "! Mandatory parameter not filled in\n";
return 1;
}
next if $format_not_respected->();
next if $missing_mandatory_param->();
etc...
основная забота состоит в том, чтобы сохранить код читаемым.
Если вы можете получить читаемый код с вложенными операторами if, продолжайте. Но всегда сохраняйте здравый смысл.
if($input ne '' && ($input !~ $_[3] || $input =~ /'.+'/)) {
print "! Format not respected. Match : /$_[3]/ (without \' \')\n";
next;
}
if($input eq '') {
if($_[2] eq 'NULL') {
if($_[1] eq 'y'){
print "! Mandatory parameter not filled in\n";
next;
}
print "+ Ignoring parameter.\n";
$input = '';
} else {
print "+ Using default value\n";
$input = $_[2];
}
}
обычной практикой является определение констант для индексов массива, и дать им осмысленные имена. Например:
use constant MANDATORY => 1,
DEFAULT => 2,
PATTERN => 3;
...
if($_[DEFAULT] eq 'NULL') {
...
}
что касается вложенности-вы должны часто пытаться уменьшить отступ (что означает сохранение низкого уровня вложенности), но никогда не делайте этого за счет сохранения кода понятным. У меня нет проблем с уровнем вложенности, но это тоже лишь небольшой отрезок кода. Если это действительно проблема, вы можете разбить условия на отдельные подпрограммы.
если логика требует вложенного оператора if, то я думаю, что с ними нет ничего плохого.
тем не менее, вы можете улучшить читаемость вашего кода с помощью
- используя только немного больше белого пространства и
- используя свои собственные переменные вместо работы непосредственно на @_
разве это не более читабельно?
98 if ($input eq '') {
99 if ($default eq 'NULL'){
100 if ($input eq 'y'){
101 print "! Mandatory parameter not filled in\n";
102 next;
103 }
104 else {
105 print "+ Ignoring parameter.\n";
106 $input = '';
107 }
108 }
109 else {
110 print "+ Using default value\n";
111 $input = $default;
112 }
113 }
114 elsif ($input !~ $foo || $input =~ /'.+'/) {
115 print "! Format not respected. Match : /$foo/ (without \' \')\n";
116 next;
117 }
118 }
учитывая, что вы, вероятно, будете делать спагетти goto
в противном случае, абсолютно нет.
что может быть лучше корпус переключателя.
вы можете упростить до следующего, если вам не нравятся все остальные.
if($input eq ''){
$input = $_[2];
$output = "+ Using default value\n";
if($_[2] eq 'NULL'){
$input = '';
$output = "+ Ignoring parameter.\n";
if($_[1] eq 'y'){
$output = "! Mandatory parameter not filled in\n";
}
}
}
elsif($input !~ $_[3] || $input =~ /'.+'/){
$output = "! Format not respected. Match : /$_[3]/ (without \' \')\n";
}
print $output;
Я думаю, что главная (если не единственная) причина для беспокойства regardong вложенности и сложности алгоритма. В других случаях вы должны беспокоиться о читаемости и ремонтопригодности, которые могут быть адресованы с комментариями и отступами propoer.
Я всегда нахожу хорошее упражнение в ремонтопригодности для чтения старого кода, не только для обратной связи по читаемости, но и по технике...
Я полагаю, вы могли бы сделать логические комбинации, чтобы сгладить его:
if(($input eq '')&&($_[2] eq 'NULL')&&($_[1] eq 'y')){
print "! Mandatory parameter not filled in\n";
next;
}
elsif(($input eq '')&&($_[2] eq 'NULL')){
print "+ Ignoring parameter.\n";
$input = '';
}
elsif($input eq ''){
print "+ Using default value\n";
$input = $_[2];
next;
}
elsif($input !~ $_[3] || $input =~ /'.+'/){
print "! Format not respected. Match : /$_[3]/ (without \' \')\n";
}
print $output;
затем вы можете использовать переключатель, чтобы сделать его немного лучше.