NOME |
perlsyn - La sintassi del Perl
Un programma Perl consiste in una sequenza di dichiarazioni e istruzioni che vengono eseguite dall'inizio alla fine. Cicli, subroutine e altre strutture di controllo vi permettono di saltare all'interno del codice.
Perl è un linguaggio free-form [A forma libera, NdT], potete formattarlo e indentarlo come preferite. Lo spazio bianco serve generalmente a separare i simboli, diversamente da altri linguaggi come Python dove è un'importante parte della sintassi.
Molti degli elementi sintattici del Perl sono opzionali. Piuttosto che richiedere di mettere le parentesi ad ogni chiamata a funzione e di dichiarare ogni variabile, spesso potete omettere questi elementi espliciti e Perl cercherà di capire cosa intendete. Questo è conosciuto come Do What I Mean [Fa quello che intendo, NdT], abbreviato DWIM. Ciò permette ai programmatori di essere pigri e di scrivere il codice in uno stile a loro confortevole.
Il Perl adotta sintassi e concetti da molti linguaggi: awk, sed, C, Bourne Shell, Smalltalk, Lisp e perfino dall'inglese. Altri linguaggi hanno preso in prestito la sintassi da Perl, in particolare le estensioni delle sue espressioni regolari. Cosí se avete già programmato con un altro linguaggio troverete frammenti familiari in Perl. Spesso funzionano allo stesso modo, ma consultate the perltrap manpage per informazioni su cosa differiscono.
Le uniche cose che avete bisogno di dichiarare in Perl sono i formati dei report e
le subroutine (e a volte nemmeno le subroutine). Una variabile contiene il valore
indefinito (undef
) finché non le viene assegnato un valore definito, cioé
qualsiasi valore divero da undef
. Quando è usato come numero, undef
viene
considerato come 0
; quando è usato come stringa viene considerato la stringa
vuota, ""
; e quando viene utilizzato come riferimento che non è stato ancora
assegnato, viene considerato come errore. Se abilitate i warnings [letterlmente
avvertimenti, con use warnings
, NdT], vi verrà notificato l'uso di un valore non
inizializzato, ogni volta che tratterete undef
come stringa o come numero.
Beh, di solito. Contesti booleani come:
my $a; if ($a) {}
sono esenti da avvertimenti (perché sono casi in cui importa la veridicità
piuttosto che la definizione). Operatori come ++
, --
, +=
, -=
e .=
,
quando operano su variabili indefinite come:
my $a; $a++;
sono anch'essi esenti da questi avvertimenti.
Una dichiarazione può essere posta ovunque si possa mettere
un'istruzione, ma non ha effetti sulla sequenza primaria delle istruzioni--le dichiarazioni
hanno tutte effetto al momento della compilazione. Tipicamente tutte le dichiarazioni
vengono poste all'inizio o alla fine di uno script. Tuttavia, se state usando una variabile
lessicale privata creata con my()
dovete assicurarvi che la definizione del vostro
formato o della subroutine sia nello stesso blocco del my
per essere in grado di accedere
a queste variabili private.
Dichiarare una subroutine permette di usare il nome di quella subroutine come operatore
di lista da quel punto in poi del programma. Potete dichiarare una subroutine senza
definirla usando sub nome
, così:
sub mionome; $io = mionome $0 or die "impossibile utilizzare mionome";
Va notato che mionome()
funziona come operatore di lista, non come operatore unario;
quindi, in questo caso, state attenti ad usare or
invece di ||
. Comunque, se
dichiaraste la subroutine come sub mionome ($)
, allora mionome
funzionerebbe
come operatore unario, così sia or
che ||
andrebbero bene.
Le dichiarazioni delle subroutine possono anche essere caricate con l'istruzione
require
, oppure sia caricate che importate nel vostro spazio dei nomi con
l'istruzione use
. Consultate the perlmod manpage per ulteriori dettagli.
Una sequenza di istruzioni può contenere delle dichiarazioni di variabili private, ma a parte questa funzione le dichiarazioni esse agiscono come istruzioni ordinarie, e vengono elaborate con il resto come se fossero istruzioni ordinarie. Questo significa che in realtà hanno degli effetti sia durante la compilazione che durante l'esecuzione.
Il testo, dal carattere "#"
sino alla fine della riga, è un commento e viene
ignorato. Le eccezioni includono "#"
all'interno di una stringa o di un'espressione
regolare.
L'unico tipo di istruzione semplice è un'espressione valutata per i suoi
effetti secondari. Ogni istruzione semplice deve terminare con un punto e virgola, salvo che
sia l'istruzione finale in un blocco nel quel caso è opzionale. (Un punto
e virgola è tuttavia incoraggiato se il blocco è lungo più di
una riga, così potete eventualmente aggiungere un'altra riga). Da notare che
ci sono operatori come eval {}
e do {}
che sembrano istruzioni composte, ma non
lo sono (sono solo TERMINI in un espressione), e perciò necessitano di un
indicatore di terminazione explicito se sono usati come ultimo elemento in una espressione.
Il numero 0, le stringhe '0'
e ''
, la lista vuota ()
e undef
risultano
tutti falsi in un contesto booleano. Tutti gli altri valori sono veri.
La negazione di un valore vero attraverso !
o not
restituisce un
valore falso speciale. Quando valutato come stringa viene trattato come ''
,
ma come numero è considerato pari a 0.
Qualunque instruzione semplice può eventualmente essere seguita da un SINGOLO modificatore, subito prima del punto e virgola finale (o della fine del blocco). I possibili modificatori solo:
if ESPRESSIONE unless ESPRESSIONE while ESPRESSIONE until ESPRESSIONE foreach LISTA
L'ESPRESSIONE
che segue il modificatore è detta ``condizione''.
La sua veridicità o falsità determina il modo in cui
il modificatore dovrà comportarsi.
if
esegue l'istruzione una volta se e solo se la condizione è vera.
unless
è l'opposto, ed esegue l'istruzione salvo che l'istruzione
risulti vera (ossia, se la condizione è falsa).
print "I basset hound hanno lunghe orecchie" if length $orecchie >= 10; vai_fuori() and gioca() unless $sta_piovendo;
Il modificatore foreach
è un iteratore: esegue l'istruzione una volta
per ogni elemento nella LISTA (con $_
che diventa un alias di ciascun elemento,
volta per volta).
print "Ciao $_!\n" foreach qw(mondo Dolly infermiera);
while
ripete l'istruzione finché la condizione è vera.
until
fa l'opposto, cioé ripete l'istruzione fermandosi quando
la condizione risulta vera.
# Ciascuna istruzione conta da 0 a 10. print $i++ while $i <= 10; print $j++ until $j > 10;
I modificatori while
e until
hanno la tipica semantica del ``ciclo while
''
(la condizione è valutata per prima), eccetto quando è applicata ad un BLOCCO do
(oppure all'uso deprecato dell'istruzione do
-SUBROUTINE), nel qual caso il blocco
viene eseguito una volta prima che sia valutata la condizione.
Così potete scrivere cicli come:
do { $riga = <STDIN>; # ... } until $riga eq ".\n";
Vedete do in the perlfunc manpage. Osservate inoltre che le istruzioni di
controllo di ciclo descritte in seguito NON funzioneranno con questo
costrutto, perché i modificatori non accettano etichette di ciclo.
Spiacenti. Potete sempre mettere un altro blocco all'interno (per next
)
o all'esterno (per last
) per fare questo genere di cose. Per next
basta raddoppiare le parentesi graffe:
do {{ next if $x == $y; # qui si fa qualcosa }} until $x++ > $z;
Per last
dovete essere più elaborati:
CICLO: { do { last if $x = $y**2; # qui si fa qualcosa } while $x++ <= $z; }
NOTA: Il comportamento di un'istruzione my
modificata da un
modificatore di istruzione o da un costrutto di ciclo (ad esempio,
my $x if ...
) è indefinito. Il valore della variabile my
può essere undef
, un qualunque valore assegnato in precedenza, o
forse qualsiasi altra cosa. Non ci contate. Versioni future di
perl potrebbero fare cose differenti rispetto alla versione che state
utilizzando ora. Occhio ai dragoni.
In Perl, una sequenza di istruzioni che definisce uno scope viene chiamata
blocco. A volte un blocco è delimitato dal file che lo contiene (nel caso di
un file richiesto [con require
, NdT], o il programma nella sua interezza),
ed a volte un blocco è delimitato dalla lunghezza di una stringa (nel caso di
una eval
).
In generale, però, un blocco è delimitato da parentesi graffe. Chiameremo questo costrutto sintattico un BLOCCO.
Le istruzioni composite che seguono possono essere utilizzate per controllare il flusso del programma:
if (ESPRESSIONE) BLOCCO if (ESPRESSIONE) BLOCCO else BLOCCO if (ESPRESSIONE) BLOCCO elsif (ESPRESSIONE) BLOCCO ... else BLOCCO ETICHETTA while (ESPRESSIONE) BLOCCO ETICHETTA while (ESPRESSIONE) BLOCCO continue BLOCCO ETICHETTA until (ESPRESSIONE) BLOCCO ETICHETTA until (ESPRESSIONE) BLOCCO continue BLOCCO ETICHETTA for (ESPRESSIONE; ESPRESSIONE; ESPRESSIONE) BLOCCO ETICHETTA foreach VAR (LIST) BLOCCO ETICHETTA foreach VAR (LIST) BLOCCO continue BLOCCO ETICHETTA BLOCCO continue BLOCCO
Osservate che, contrariamente a C e Pascal, queste sono definite in termini di BLOCCHI, non di istruzioni. Ciò significa che le parentesi graffe sono obbligatorie -- non sono ammesse istruzioni pendenti. Se volete scrivere condizioni senza parentesi graffe ci sono parecchi altri modi di farlo. Le seguenti istruzioni fanno tutte la stessa cosa:
if (!open(PIPPO)) { die "Errore in open $PIPPO: $!"; } die "Errore in open $PIPPO: $!" unless open(PIPPO); open(PIPPO) or die "Errore in open $PIPPO: $!"; # PIPPO o morte! open(PIPPO) ? 'hi mom' : die "Errore in open $PIPPO: $!"; # un po' esotica, quest'ultima
L'istruzione if
è banale. Poiché i BLOCCHI sono sempre circondati da
parentesi graffe, non c'è mai ambiguità su quale if
sia associato ad
un particolare else
. Se utilizzate unless
al posto di if
, il senso
del test è invertito.
L'istruzione while
esegue il blocco finché l'espressione è vera (ossia,
non viene valutata come la stringa nulla ""
o 0
o "0"
[o anche undef
, NdT]). L'istruzione until
esegue il blocco
finché l'espressione è falsa.
L'ETICHETTA è opzionale e, se presente, consiste in un identificatore seguito
da un carattere due-punti. L'ETICHETTA identifica il ciclo per le
istruzioni di controllo dei cicli next
, last
e redo
.
Se l'ETICHETTA viene omessa, l'istruzione di controllo del ciclo si riferisce
al ciclo più interno che la racchiude. Tutto ciò può implicare uno
sguardo dinamico allo stack di chiamata in esecuzione per trovare
l'ETICHETTA giusta. Un comportamento così disperato produce un
avvertimento [``warning'', NdT] se utilizzate la direttiva
use warnings
o l'opzione -w
.
Se c'è un BLOCCO continue
, viene sempre eseguito immediatamente prima
che la condizione venga valutata di nuovo. Per questo motivo, può essere
utilizzato per incrementare la variabile di un ciclo, anche quando il ciclo
viene fatto continuare con un'istruzione next
.
Il comando next
fa partire l'iterazione successiva del ciclo:
RIGA: while (<STDIN>) { next RIGA if /^#/; # Scarta i commenti #... }
Il comando last
esce immediatamente dal ciclo in questione. Il blocco
continue
, se presente, non viene eseguito:
RIGA: while (<STDIN>) { last RIGA if /^$/; # esci quando hai finito con l'intestazione # ... }
Il comando redo
fa ripartire il ciclo senza valuatare la condizione
di nuovo. Il blocco continue
, se presente, non viene eseguito.
Questo comando viene normalmente utilizzato da programmi che vogliono
mentire a se stessi su quanto è stato appena inserito.
Ad esempio, quando elaborate un file come /etc/termcap. Se le vostre righe di ingresso potessero terminare con backslash per indicare continuazione, vorreste saltare avanti e prendere il record successivo.
while (<>) { chomp; if (s/\\$//) { $_ .= <>; redo unless eof(); } # ora si elabora $_ }
che è una scorciatoia Perl per la versione più esplicita:
RIGA: while (defined($riga = <ARGV>)) { chomp($riga); if ($riga =~ s/\\$//) { $riga .= <ARGV>; redo RIGA unless eof(); # non eof(ARGV)! } # ora si elabora $riga }
Osservate che se ci fosse un blocco continue
in questo codice,
verrebbe eseguito solo in corrispondenza delle righe scartate
dall'espressione regolare (poiché redo
salta il blocco continue
).
Un blocco continue
viene spesso utilizzato per riazzerare i
contatori di riga o dei match di singoli ?pattern?
:
# ispirato da :1,$g/fred/s//WILMA/ while (<>) { ?(fred)? && s//WILMA $1 WILMA/; ?(barney)? && s//BETTY $1 BETTY/; ?(homer)? && s//MARGE $1 MARGE/; } continue { print "$ARGV $.: $_"; close ARGV if eof(); # riazzera $. reset if eof(); # riazzera ?pattern? }
Se si sostituisce la parola until
a while
il senso del test
è invertito, ma la condizione viene sempre verificata prima della
prima iterazione.
Le istruzioni di controllo di ciclo non funzionano all'interno di
if
o unless
, poiché questi non sono cicli. Potete però raddoppiare
le parentesi graffe per renderli tali.
if (/pattern/) {{ last if /fred/; next if /barney/; # stesso effetto di "last", ma non documenta altrettanto bene # qui si fa qualcosa }}
Questo comportamento si ha perché quel blocco, di per sé, agisce come un ciclo che viene eseguito una volta sola, consultate BLOCCHI base ed Istruzioni Switch.
La forma while/if BLOCCO BLOCCO
, disponibile in Perl 4, non esiste
più. Rimpiazzate ogni occorrenza di if BLOCCO
con
if (do BLOCCO)
.
I cicli for
stile C in Perl funzionano come il corrispondente
ciclo while
; ciò significa che questo:
for ($i = 1; $i < 10; $i++) { # ... }
è la stessa cosa di:
$i = 1; while ($i < 10) { # ... } continue { $i++; }
C'è una differenza minore: se le variabili sono dichiarate con my
nella sezione di inizializzazione del for
, lo scope lessicale
di queste variabili coincide con il ciclo for
(il corpo del ciclo
e le sezioni di controllo).
Oltre al normale ciclo con l'indice di un array, for
può prestarsi
a molte altre applicazioni interessanti. Eccone una che evita
il problema in cui vi trovate se effettuate esplicitamente il test
di fine file su un descrittore di file interattivo, il che
farebbe sembrare bloccato il programma.
$su_una_tty = -t STDIN && -t STDOUT; sub richiedi { print "si'? " if $su_una_tty } for ( richiedi(); <STDIN>; richiedi() ) { # fai qualcosa }
Utilizzando readline
(o la forma ad operatore, <ESPRESSIONE>
)
come condizionali per un ciclo for
è una scorciatoia per quanto
segue. Questo comportamento coincide con quello di una condizione
in un ciclo while
.
>>
for ( richiedi(); defined( $_ = <STDIN> ); richiedi() ) { # fai qualcosa }
Il ciclo foreach
itera su una normale lista ed imposta la
variabile VAR come incarnazione di ciascun elemento della lista, in
sequenza. Se la variabile è preceduta dalla parola chiave my
, allora
essa ha lo scope di un lessicale, ed è pertanto visibile solo
all'interno del ciclo. Altrimenti, la vaiabile è implicitamente locale
al ciclo e viene ripristinata al suo valore originale una volta usciti
dal ciclo. Se la variabile era stata precedentemente dichiarata con
my
, viene utilizzata quella variabile invece che quella globale, ma
è sempre localizzata al ciclo. Questa localizzazione implicita avviene
solo in un ciclo foreach
.
La parola chiave foreach
è in realtà un sinonimo per la parola chiave
for
, di modo che potete utilizzare foreach
per privilegiare la
leggibilità o for
per maggiore brevità. (O perché la shell Bourne
potrebbe esservi più familiare di csh, quindi scrivere for
verrebbe più naturale). Se VAR è omessa, $_
viene impostata a
ciascun valore.
Se un qualunque elemento di LISTA è un lvalue [valore utilizzabile
alla sinistra di un'assegnazione, NdT], potete modificarlo attraverso
VAR all'interno del ciclo. Di contro, se un qualsiasi elemento in LISTA
NON è un lvalue, qualsiasi tentativo di modificare quell'elemento
fallirà. In altre parole, la variabile indice in un ciclo foreach
è
un alias implicito per ciascun elemento nella lista su cui state
iterando.
Se una qualunque parte di LISTA è un array, foreach
rimarrà decisamente
confuso se aggiungete o rimuovete elementi all'interno del corpo del ciclo,
ad esempio utilizzando splice
. Per questo motivo, non fatelo.
foreach
, probabilmente, non farà quel che vi aspettate se VAR è
una variabile su cui è stata chiamata tie
o se è un'altra variabile
speciale. Non fate nemmeno questo.
Esempi:
for (@ary) { s/foo/bar/ }
for my $elem (@elementi) { $elem *= 2; }
for $contatore (10,9,8,7,6,5,4,3,2,1,'BOOM') { print $contatore, "\n"; sleep(1); }
for (1..15) { print "Buon Natale\n"; }
foreach $elemento (split(/:[\\\n:]*/, $ENV{TERMCAP})) { print "Elemento: $elemento\n"; }
Ecco come un programmatore C potrebbe scrivere un particolare algoritmo in Perl:
for (my $i = 0; $i < @ary1; $i++) { for (my $j = 0; $j < @ary2; $j++) { if ($ary1[$i] > $ary2[$j]) { last; # non si puE<ograve> andare su quello esterno :-( } $ary1[$i] += $ary2[$j]; } # ecco dove mi porta quel last }
Ecco invece come potrebbe farlo un programmatore Perl più a suo agio con l'idioma:
ESTERNO: for my $wid (@ary1) { INTERNO: for my $jet (@ary2) { next ESTERNO if $wid > $jet; $wid += $jet; } }
Vedete quant'è più facile? È più pulito, sicuro e veloce.
È più pulito perché ha meno rumore. È più sicuro
perché se più tardi si aggiunge codice fra il ciclo interno e quello esterno,
il nuovo codice non verrà eseguito accidentalmente. Il next
itera esplicitamente
il ciclo esterno invece che ridursi a terminare quello interno. Ed è più
veloce perché Perl esegue un'istruzione foreach
più rapidamente di quanto
farebbe un ciclo for
equivalente.
Un BLOCCO di per sé (etichettato o meno) è semanticamente equivalente ad
un ciclo che viene eseguito una volta. Per questo motivo potete
utilizzare una qualunque delle istruzioni di controllo di ciclo al suo
interno, per lasciare o far ripartire il blocco. (Osservate che
ciò NON vale per eval{}
e sub{}
, o contrariamente al credo
popolare per i blocchi do{}
, che NON contano come cicli). Il
blocco continue
è opzionale.
Il costrutto BLOCCO è particolarmente utile per realizzare strutture
case
[istruzione C che marca una fra più parti di codice differenti
a seconda del valore di un'espressione, NdT].
SWITCH: { if (/^abc/) { $abc = 1; last SWITCH; } if (/^def/) { $def = 1; last SWITCH; } if (/^xyz/) { $xyz = 1; last SWITCH; } $niente = 1; }
Non esite alcuna istruzione switch
ufficiale in Perl, perché ci
sono già molti modi per scrivere qualcosa di equivalente.
Ad ogni modo, a partire da Perl 5.8, per avere switch e case
si
può utilizzare l'estensione Switch e dichiarare:
use Switch;
dopo di che si hanno switch e case. Non è veloce come potrebbe perché non è veramente parte del linguaggio (è realizzato utilizzando dei filtri sul codice sorgente), ma è disponibile e molto flessibile.
In aggiunta al costrutto BLOCCO citato, potreste anche scrivere
SWITCH: { $abc = 1, last SWITCH if /^abc/; $def = 1, last SWITCH if /^def/; $xyz = 1, last SWITCH if /^xyz/; $niente = 1; }
(Non è, in realtà, strano come sembra una volta compreso che potete utilizzare ``operatori'' di controllo del ciclo all'interno di un'espressione. Si sta solo utilizzando l'operatore binario ``virgola'' in contesto scalare. Consultate Comma Operator in the perlop manpage [``L'operatore virgola'', NdT]).
o
SWITCH: { /^abc/ && do { $abc = 1; last SWITCH; }; /^def/ && do { $def = 1; last SWITCH; }; /^xyz/ && do { $xyz = 1; last SWITCH; }; $niente = 1; }
o formattato in modo che risalti di più come un'istruzione switch
``propria'':
SWITCH: { /^abc/ && do { $abc = 1; last SWITCH; };
/^def/ && do { $def = 1; last SWITCH; };
/^xyz/ && do { $xyz = 1; last SWITCH; }; $niente = 1; }
o
SWITCH: { /^abc/ and $abc = 1, last SWITCH; /^def/ and $def = 1, last SWITCH; /^xyz/ and $xyz = 1, last SWITCH; $niente = 1; }
o anche, orrore,
if (/^abc/) { $abc = 1 } elsif (/^def/) { $def = 1 } elsif (/^xyz/) { $xyz = 1 } else { $niente = 1 }
Un idioma comune per un'istruzione switch
consiste nell'utilizzare
l'aliasing di foreach
per effetture assegnazioni temporanee a $_
ed ottenere un matching conveniente:
SWITCH: for ($dove) { /Nei Nomi delle Carte/ && do { push @flags, '-e'; last; }; /Ovunque/ && do { push @flags, '-h'; last; }; /Nelle Regole/ && do { last; }; die "valore sconosciuto per la variabile dove: `$dove'"; }
Un altro approccio interessante per un'istruzione switch consiste
nel fare in modo che un blocco do
restituisca il valore corretto:
$amode = do { if ($flag & O_RDONLY) { "r" } # XXX: non e` 0? elsif ($flag & O_WRONLY) { ($flag & O_APPEND) ? "a" : "w" } elsif ($flag & O_RDWR) { if ($flag & O_CREAT) { "w+" } else { ($flag & O_APPEND) ? "a+" : "r+" } } };
O
print do { ($flags & O_WRONLY) ? "write-only" : ($flags & O_RDWR) ? "read-write" : "read-only"; };
O se siete certi che tutte le clausole in &&
sono vere, potete utilizzare
qualcosa come quello che segue, che ``cambia'' in base al valore della variabile
di ambiente HTTP_USER_AGENT
.
#!/usr/bin/perl # prendi la pagina del file jargon in base al browser $dir = 'http://www.wins.uva.nl/~mes/jargon'; for ($ENV{HTTP_USER_AGENT}) { $page = /Mac/ && 'm/Macintrash.html' || /Win(dows )?NT/ && 'e/evilandrude.html' || /Win|MSIE|WebTV/ && 'm/MicroslothWindows.html' || /Linux/ && 'l/Linux.html' || /HP-UX/ && 'h/HP-SUX.html' || /SunOS/ && 's/ScumOS.html' || 'a/AppendixB.html'; } print "Location: $dir/$page\015\012\015\012";
Questo tipo di istruzione switch funziona solamente quando sapete che
le clausole &&
saranno vere. Se non siete sicuri, dovreste affidarvi
all'esempio precedente con ?:
.
Potreste anche prendere in considerazione lo scrivere una hash contenente
riferimenti a subroutine invece di realizzare un'instruzione switch
.
Sebbene non sia adatta ai deboli di cuore, Perl supporta un'istruzione
goto
. Esiste in tre forme: goto
-ETICHETTA, goto
-ESPRESSIONE e
goto
-&NOME. Un'etichetta di ciclo non costituisce, in realtà, un
valido obiettivo per una goto
; è solo il nome del ciclo.
La forma goto
-ETICHETTA trova l'istruzione etichettata con ETICHETTA
e riprende l'esecuzione da lì. Non può essere utilizzata per andare
in un qualunque costrutto che richieda inizializzazione, come una
subroutine o un ciclo foreach
. Non può nemmeno essere utilizzata per
andare in un costrutto che viene ottimizzato. Può invece essere usata per
andare praticamente in qualsiasi posto che si trovi nello scope
dinamico, inclusa l'uscita dalle subroutine. Ma di solito è meglio
utilizzare altri costrutti come last
o die
. L'autore di Perl
non ha mai sentito il bisogno di utilizzare questa forma di
goto
(in Perl perlomeno -- in C è un'altra storia).
La forma goto
-ESPRESSIONE si aspetta il nome di un'etichetta, il cui
scope verrà risolto dinamicamente. Questo consente di avere dei
goto
calcolati come in FORTRAN, ma non è nesessariamente raccomandato
se cercate di ottimizzare il codice rispetto alla manutenibilità:
goto(("PIPPO", "PLUTO", "TOPOLINO")[$i]);
La forma goto
-&NOME è estremamente magica, e sostituisce una chiamata
alla subroutine nominata al posto della subroutine attualmente in esecuzione.
Questo meccanismo viene utilizzato dalle subroutine AUTOLOAD()
che vogliono
caricare un'altra subroutine e far finta che tale altra subroutine sia stata
chiamata sin dall'inizio (eccetto che eventuali modifiche a @_
nella
subroutine corrente siano propagate anche nell'altra). Dopo una goto
,
nemmeno caller()
sarà in grado di dire che questa routine è stata
chiamata prima.
In quasi tutti i casi come questo, è di solito un'idea di gran lunga migliore
utilizzare i meccanismi di controllo di flusso dati da next
, last
o
redo
piuttosto che abbassarsi al livello di goto
. Per certe applicazioni,
la coppia di catch e throw
[terminologia utilizzata per parlare della
gestione delle eccezioni in molti linguaggi, fra cui C++ e Java, NdT]
fornita da eval{}
e die()
per l'elaborazione delle eccezioni può
risultare un approccio prudente.
Perl ha un meccanismo per inframmezzare la documentazione con il codice sorgente. Nei punti in cui si aspetta l'inizio di una nuova istruzione, se il compilatore incontra una riga che comincia con un segno uguale ed una parola, come questa:
=head1 Ecco che arrivano i Pod!
allora il testo nella riga e tutto quello che segue fino ad una riga
che comincia con =cut
(riga compresa) sarà ignorato. Il formato
del testo incluso è descritto in the perlpod manpage.
Ciò vi consente di inframmezzare liberamente codice e documentazione, come in
=item spippola($)
La funzione spippola() si comportera` nella piE<ugrave> spettacolare delle forme che possiate mai immaginare, senza nemmeno escludere forme pirotecniche cibernetiche.
=cut torniamo al compilatore, niente di questa roba pod!
sub spippola($) { my $cosetta = shift; # ......... }
Osservate che i traduttori pod dovrebbero guardare solo ai paragrafi che iniziano con una direttiva pod (rende più semplice il parsing), laddove il compilatore di fatto sa rilevare delle eccezioni pod anche nel bel mezzo di un paragrafo. Questo signifca che la roba segreta che segue verrà ignorata sia dal compilatore che dai traduttori.
$a=3; =roba segreta warn "Ne' CODICE ne' POD!?" =cut indietro print "preso $a\n";
Probabilmente, però, non dovreste contare troppo sul fatto che l'istruzione
warn()
qui sopra verrà eliminata come pod per sempre. Non tutti i
traduttori di pod si comportano bene a questo proposito, e forse
il compilatore diverrà più bizzoso.
Si possono anche utilizzare le direttive pod per commentare rapidamente una sezione di codice.
Perl può elaborare direttive di riga, molto similmente al preprocessore C.
Utilizzando questo meccanismo, è possibile controllare l'idea che Perl ha
dei nomi dei file e dei numeri di riga nei messaggi di errore o di avviso
(specialmente per quelle stringhe che sono elaborate con eval()
). La
sintassi per questo meccanismo è la stessa che per la maggior parte
dei preprocessori C: aderisce all'espressione regolare
# esempio: '# riga 42 "nuovo_nomefile.plx"' /^\# \s* line \s+ (\d+) \s* (?:\s("?)([^"]+)\2)? \s* $/x
laddove $1
rappresenta il numero di riga per la prossima riga, e
$3
rappresenta il nome del file opzionale (specificato con o
senza virgolette).
C'è una cosa piuttosto ovvia da cui guardarsi quando si utilizza la direttiva
line
: i debugger ed i profiler [programmi che analizzano le prestazioni
delle varie sezioni del programma, NdT] mostreranno solo l'ultima riga
riga sorgente come presente ad un particolare numero di riga in un dato
file. Dovete prestare attenzione a non generare delle collisioni nei
numeri di riga nel codice su cui avrete poi voglia di effettuare il debug.
Ecco alcuni esempi che dovreste essere in grado di digitare nella vostra shell di comando:
% perl # line 200 "bzzzt" # il `#' nella riga precedente deve essere il primo carattere nella riga die 'pippo'; __END__ pippo at bzzzt line 201.
% perl # line 200 "bzzzt" eval qq[\n#line 2001 ""\ndie 'pippo']; print $@; __END__ pippo at - line 2001.
% perl eval qq[\n#line 200 "pippo pluto"\ndie 'pippo']; print $@; __END__ pippo at pippo pluto line 200.
% perl # line 345 "miao" eval "\n#riga " . __LINE__ . ' "' . __FILE__ ."\"\ndie 'pippo'"; print $@; __END__ pippo at miao line 345.
La versione su cui si basa questa traduzione è ottenibile con:
perl -MPOD2::IT -e print_pod perlsyn
Per maggiori informazioni sul progetto di traduzione in italiano si veda http://pod2it.sourceforge.net/ .
Traduzione a cura di kral e Flavio Poletti.
Revisione a cura di dree.
NOME |