2009-07-28 3 views
6

Sto facendo un po 'di Perl e vedere le mie dichiarazioni "se" nidificate mi sta facendo impazzire. Sono riuscito a ridurre alcuni di loro con blocchi di guardia in un'altra sezione, ma sono bloccato qui.Dovrei evitare nidificare le istruzioni in Perl?

Pensi che possa lasciare il codice così com'è, oppure esiste un modo "corretto" di rifattorizzare quanto segue? (Ammetto anche di essere relativamente nuovo a Perl)

Questa è in realtà una subroutine che richiede l'input dell'utente su ciascun parametro di una lista (file esterno). $ [3] è il modello di corrispondenza, $ [2] è il valore predefinito per il parametro considerato (NULL se non ce n'è), $ _ [1] specifica se è obbligatorio o meno. la frase 'next' si riferisce al prossimo parametro read (while loop).

Con l'aiuto di tutti (grazie!), Ecco la versione più recente.

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

Che cosa ti sta facendo impazzire di questi if nidificati? – innaM

+0

Non lo so, mi sembra che ci sia un altro modo di scrivere che ... –

risposta

10

Ecco una versione leggermente più leggibile del caos risposta:

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

I punti chiave sono:

  • Non è necessario altro se si sta uscendo l'anello di corrente con successivo
  • I casi eccezionali devono essere gestiti per primi
  • È possibile Migliorare notevolmente la leggibilità utilizzando variabili denominate
+0

Grazie per quello. Le nostre risposte hanno attraversato (vedi il mio primo post di modifica). Btw, nel mio codice, $ is_required obbliga l'utente a compilare, non è un reclamo: p (Non cambia nulla e non hai letto l'intera subroutine) –

+0

Mi dispiace di postare due post, ma mi piace il tuo modo di commentare ; e "non hai letto" intendevo "non ho postato". –

+0

Grazie, anche se non posso rivendicare alcun credito. Lo stile di commento è di Damian Conway - l'ho adottato dopo aver letto le sue cose perché mi piaceva anche a me. ;) –

1

Se logica necessaria nidificato if allora credo che non v'è nulla di sbagliato con loro.

Tuttavia, si potrebbe migliorare la leggibilità del codice

  1. Utilizzando solo un po 'più spazio bianco e
  2. Utilizzando le proprie variabili invece di operare direttamente sul @_

Isn' questo è un po 'più leggibile?

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

Informazioni sul punto 1., sto usando Perltidy ogni tanto. Attualmente sto cercando di risolvere i problemi ed eseguire il debug in anticipo. 2. Ho letto (nel libro di O'reilly e altrove) che $ _ e $ @ sono stati ampiamente utilizzati, senza menzionare alcuno svantaggio? –

+0

1. Cercare di risolvere i problemi è molto più semplice con un codice di facile lettura. 2. Lo svantaggio è la leggibilità. Quando sostituisci i vari usi di $ _ [x], ad esempio, ho subito notato che la tua descrizione di ciò che queste variabili contengono non può essere completamente corretta. – innaM

+0

1. Hai assolutamente ragione. Mi piace il codice così com'è, ma sarà sicuramente mantenuto da altri (prima tu). 2. @_ è una matrice che contiene l'elenco dei parametri passati (per valore) alla funzione. Destra ? Per quanto riguarda $ _, lo sto usando solo quando r/w (dentro) un filehandle. –

2

È prassi comune definire le costanti per gli indici di array e assegnare loro nomi significativi. Come ad esempio:

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

Per quanto riguarda la nidificazione - Si dovrebbe spesso cercare di ridurre il trattino (cioè mantenendo il livello di nidificazione basso), ma mai farlo a scapito di mantenere il codice comprensibile. Non ho alcun problema con il livello di nidificazione, ma questo è anche solo un piccolo taglio del codice. Se è davvero un problema, puoi suddividere le condizioni in subroutine separate.

+0

Come ho detto, è una subroutine, tutte le mie variabili sono locali. Quindi non posso usare la frase "use"? L'annidamento non è un problema per il resto del codice, per fortuna. Grazie per la tua risposta. –

+1

'use constant' presenta alcuni svantaggi. Le costanti create con la costante di utilizzo non possono essere interpolate (ad esempio nelle stringhe), in quanto non hanno sigillo e non sono con scope lessicale in fase di runtime. Sono scope del pacchetto e generate in fase di compilazione. Questo è un problema se hai un set costante in fase di runtime, ad es. da una funzione. Questo è descritto molto meglio, e con esempi eccellenti, nel libro "Perl Best Practices", di Damian Conway. –

0

Dato che probabilmente fare uno spaghetti goto altrimenti Assolutamente No.

Quale potrebbe essere migliore è un switch case.

+0

Ho imparato la lezione: goto è HELL. ;) Non ci ho mai pensato. Switch case non si applica qui, poiché sto testando 4 variabili diverse. –

+0

Non intendete 'given' /' when'? –

+0

Non è implementato solo con 'use feature' o 'use switch' 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

Mi piace! Grazie ! (tranne il cuddled altro: p) –

0

si potrebbe semplificare a quanto segue se non ti piace tutto il resto.

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, ha perso una certa leggibilità. Grazie comunque;) –

3

La preoccupazione principale è mantenere il codice leggibile.

Se è possibile ottenere codice leggibile con istruzioni nidificate if, procedere. Ma mantenere il buon senso attivo in ogni momento.

+0

Se dovessi mantenere il mio codice, avresti difficoltà a farlo? –

+0

@Isaac, no. (Ma io sono addestrato a mantenere un codice difficile da leggere, quindi non sono un buon riferimento). –

-2

suppongo che si possa fare combinazioni logiche di appiattire fuori:

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; 

allora si potrebbe utilizzare un interruttore per renderlo un po 'meglio.

+0

Questa in realtà era la mia versione precedente, tuttavia i test "&&" non mi andavano bene. –

+0

Ciò riduce sia la leggibilità che la velocità. – Imagist

+0

Questo non è nemmeno Perl. Perl non ha 'elseif' solo' elsif'. –

0

Penso che la principale (se non solo) ragione per le preoccupazioni relative al nesting è la complessità dell'algoritmo. Negli altri casi dovresti preoccuparti della leggibilità e della manutenibilità, che possono essere affrontate con commenti e rientri propoer.

trovo sempre un buon esercizio di mantenibilità per leggere vecchio codice di mine, non solo per un feedback sulla leggibilità, ma anche sulla tecnica ...

4

Un approccio alternativo che a volte aiuta con la leggibilità è quello di mettere alcuni o tutti dei rami in riferimenti di codice ben definiti. Ecco un inizio sull'idea:

$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

Non lo sapevo, grazie! Anche se nel mio caso, sono già in una subroutine (nidificato if o sub-sub-routine, ovvero la domanda), che potrebbe rivelarsi utile per altri script. –

+0

Questo comporrà un paio di sottotitoli ogni volta che chiami questa funzione - è davvero * quello che vuoi fare? È un'idea chiara - e ti ho dato una risposta, ma se questo verrà chiamato molto, è meglio non usare il comportamento di cattura. (Credo.) – Axeman