2009-07-28 8 views
6

Robię trochę Perla i widząc moje zagnieżdżone stwierdzenia "jeśli" doprowadza mnie do szału. Udało mi się zmniejszyć niektóre z nich z blokami strażniczymi w innej sekcji, ale utknąłem tutaj.Czy należy unikać zagnieżdżonych instrukcji if w Perlu?

Czy sądzisz, że mogę pozostawić kod w niezmienionym stanie, lub czy istnieje "właściwy" sposób na refaktoryzację? (Przyznaję również, że jest to relatywnie nowy produkt w Perlu).

To jest właściwie podprogram z pytaniem o dane wejściowe użytkownika dla każdego parametru listy (plik zewnętrzny). $ [3] jest pasującym wzorcem, $ [2] jest domyślną wartością dla rozważanego parametru (NULL, jeśli nie ma), $ _ [1] określa, czy jest obowiązkowe czy nie. "następna" instrukcja odnosi się do następnego odczytanego parametru (while loop).

Z pomocą wszystkich (dzięki!), Oto najnowsza wersja.

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 in\n"; 
108      next; 
109     } 
110     print "+ Ignoring parameter.\n"; 
111     $input = ''; 
112    } 
113    else { 
114     print "+ Using default value\n"; 
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 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 = $_[2]; 
112    } 
113   } 
114   elsif($input !~ $_[3] || $input =~ /'.+'/){ 
115     print "! Format not respected. Match : /$_[3]/ (without \' \')\n"; 
116     next; 
117    } 
118   } 
+1

Co dokładnie doprowadza Cię do szaleństwa z powodu zagnieżdżonych? – innaM

+0

Nie wiem, po prostu czuję, że istnieje inny sposób pisania tego ... –

Odpowiedz

10

Oto nieco bardziej czytelną wersję chaosu odpowiedź:

# 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"; 
    } 
} 

kluczowych punktów są:

  • Nie trzeba inny jeśli wyjściu z pętli prądowej z następny
  • Nadzwyczajne sprawy powinny być traktowane jako pierwsze
  • Możesz znacznie poprawiają czytelność przy użyciu nazwanych zmiennych
+0

Dzięki za to. Nasze odpowiedzi zostały skrzyżowane (patrz moja pierwsza edycja postu). Btw, w moim kodzie, $ is_required zmusza użytkownika do wypełnienia, to nie jest zarzut: p (nic nie zmienia i nie przeczytałeś całej podprocedury) –

+0

Przepraszam za podwójny post, ale podoba mi się twój sposób komentowania ; i przez "nie czytałeś" miałem na myśli "Nie napisałem". –

+0

Dzięki, chociaż nie mogę ubiegać się o żadne uznanie. Styl komentowania to Damian Conway - przyjąłem go po przeczytaniu jego rzeczy, bo też to lubiłem. ;) –

1

Jeśli logika wymagane zagnieżdżone if to chyba nie ma nic złego z nimi.

Jednakże, można poprawić czytelność kodzie poprzez

  1. Korzystanie tylko trochę więcej spacji i
  2. Przy użyciu własnych zmiennych zamiast działających bezpośrednio na @_

ISN” Czy to jest nieco bardziej czytelne?

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   } 
+0

O punkcie 1., używam Perltidy co jakiś czas. Obecnie próbuję rozwiązać problemy i wcześniej debugować. 2. Czytałem (w książce O'reilly i gdzie indziej), że $ _ i $ @ były szeroko używane, bez wymieniania jakichkolwiek wad? –

+0

1. Próba rozwiązania problemów jest łatwiejsza dzięki łatwemu do odczytania kodowi. 2. Wadą jest czytelność. Podczas zastępowania różnych zastosowań $ _ [x], np. Od razu zauważyłem, że twój opis tych zmiennych nie może być całkowicie poprawny. – innaM

+0

1. Masz absolutną rację. Podoba mi się ten kod, jaki jest, ale z pewnością będzie utrzymywany przez innych (najpierw Ciebie). 2. @_ jest tablicą zawierającą listę parametrów przekazywanych (według wartości) do funkcji. Dobrze ? Jeśli chodzi o $ _, używam go tylko wtedy, gdy r/w (w) jest uchwytem pliku. –

2

Powszechną praktyką jest definiowanie stałych dla indeksów tablic i nadawanie im znaczących nazw. Takich jak:

use constant MANDATORY => 1, 
      DEFAULT => 2, 
      PATTERN => 3; 
... 
if($_[DEFAULT] eq 'NULL') { 
    ... 
} 

miarę gniazdowania - Powinieneś często starają się zmniejszyć wcięcie (co oznacza utrzymanie poziomu zagnieżdżenia niskie), ale nigdy nie robić kosztem utrzymania kod zrozumiały. Nie mam problemu z poziomem zagnieżdżenia, ale jest to również po prostu niewielkie wycięcie twojego kodu. Jeśli to naprawdę problem, możesz podzielić warunki na osobne podprogramy.

+0

Jak już powiedziałem, jest to podprocedura, wszystkie moje zmienne są lokalne. W związku z tym nie mogę użyć instrukcji "use"? Zagnieżdżanie nie jest problemem dla reszty kodu, na szczęście. Dzięki za odpowiedź. –

+1

"Użyj stałej" ma pewne wady. Stałe utworzone za pomocą stałej stałej nie mogą być interpolowane (np. W łańcuchach), ponieważ nie mają sigila i nie są leksykalne w czasie wykonywania. Są one w pakietach i generowane podczas kompilacji. Jest to problem, jeśli masz stały zestaw w czasie wykonywania, np. przez funkcję. Zostało to opisane znacznie lepiej, z doskonałymi przykładami, w książce "Perl Best Practices" autorstwa Damiana Conwaya. –

0

Biorąc pod uwagę, że prawdopodobnie będzie zrobić spaghetti goto inaczej, absolutnie nr

Co może być lepiej jest switch case.

+0

Nauczyłem się mojej lekcji: goto to HELL. ;) Nawet o tym nie myślałem. Skrzynka przełączników tak naprawdę nie ma tutaj zastosowania, ponieważ testuję 4 różne zmienne. –

+0

Nie masz na myśli 'dany' /' kiedy'? –

+0

Czy nie jest to implementowane tylko z "funkcją użycia" lub "przełącznikiem użytkowania" perl 6.0 "? –

3
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]; 
    } 
} 
+0

Podoba mi się to! Dzięki ! (z wyjątkiem przytulonego jeszcze: p) –

0

możesz uprościć poniższe, jeśli nie lubisz wszystkich innych.

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; 
+0

imho, stracił trochę czytelności. Dzięki i tak;) –

3

Głównym problemem jest zapewnienie czytelności kodu.

Jeśli możesz uzyskać czytelny kod z zagnieżdżonymi instrukcjami if, śmiało. Ale utrzymuj zdrowy rozsądek przez cały czas.

+0

Czy musisz zachować mój kod, czy miałbyś trudności z tym? –

+0

@ Isaac, nie. (Ale jestem wyszkolony do utrzymywania trudnego do odczytania kodu, więc nie jestem dobrym referencją). –

-2

Przypuszczam, że można zrobić kombinacje logiczne do spłaszczyć go:

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; 

Następnie można użyć przełącznika, aby zrobić to trochę lepiej.

+0

To była moja poprzednia wersja, ale testy "&&" nie pasowały do ​​mnie. –

+0

Zmniejsza to zarówno czytelność, jak i szybkość. – Imagist

+0

To nie jest nawet Perl. Perl nie ma 'elseif' tylko' elsif'. –

0

Myślę, że głównym (jeśli nie tylko) powodem do obaw dotyczących zagnieżdżania jest złożoność algorytmu. W innych przypadkach powinieneś się martwić o czytelność i łatwość obsługi, do której można się odwołać za pomocą komentowania i wcięcia.

zawsze znaleźć dobre ćwiczenie w maintanability czytać stary kod z kopalni, a nie tylko do informacji zwrotnych na temat czytelności ale również na technice ...

4

Alternatywnym podejściem, że czasami pomaga czytelności jest umieszczenie niektórych lub wszystkich oddziałów w dobrze nazwanych odnośnikach do kodu. Oto początek pomysłu:

$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... 
+0

Nie wiedziałem o tym, dzięki! Nawet jeśli w moim przypadku, jestem już w podprocedurze (zagnieżdżonej jeśli lub pod-podprogram, to jest pytanie), która może się przydać w przypadku innych skryptów. –

+0

To będzie kompilacja kilku podsłuchów za każdym razem, gdy wywołasz tę funkcję - czy to * naprawdę * to, co chcesz zrobić? To zgrabny pomysł - i podjąłem decyzję, ale jeśli będzie to dużo mówić, lepiej nie używać zachowania przechwytującego. (Myślę.) – Axeman

Powiązane problemy