- NOME
- DESCRIZIONE
- È
possibile ottenere una BNF/yacc/RE del linguaggio Perl?
- http://pod2it.sourceforge.net/pods/perlfaq7.html#cosa
sono tutti quei segni di punteggiatura $@%&*, e come faccio a
sapere quando usarli
- Devo
sempre/non devo mai mettere tra virgolette le mie stringhe, oppure
usare i punti e virgola o le virgole?
- Come
tralascio alcuni valori di ritorno?
- Come
posso disabilitare temporaneamente i warning?
- Cos'è
un'estensione (extension)?
- Perché
gli operatori del Perl hanno una precedenza diversa rispetto a quelli
del C?
- Come
dichiaro/creo una struttura?
- Come
si crea un modulo?
- Come
faccio a creare una classe?
- Come
faccio a stabilire se una variabile è potenzialmente dannosa?
- Che
cos'è una chiusura?
- Cos'è
il suicidio di variabile e come si può prevenire?
- Come
faccio a passare/restituire una {Funzione, FileHandle, Array, Hash,
Metodo, Espressione Regolare}?
- Come
si crea una variabile statica?
- Qual
è la differenza tra visibilità dinamica e visibilità lessicale (o
statica)? Qual è la differenza tra
local() e my()?
- Come
posso accedere ad una variabile dinamica quando è visibile una
variabile lessicale con lo stesso nome?
- Qual
è la differenza tra il deep binding (legame profondo) e lo shallow
binding (legame superficiale)?
- Perché
``my($pippo) = <FILE>;'' non funziona bene?
- Come
si fa a ridefinire una funzione, operatore o metodo predefinito?
- Qual
è la differenza tra il chiamare una funzione con &pippo e con
pippo()?
- Come
faccio a realizzare un'istruzione switch o case?
- Come
posso intercettare gli accessi a variabili, funzioni o metodi
indefiniti?
- Perché
non si riesce a trovare un metodo incluso in questo stesso file?
- Come
posso sapere qual è il package corrente?
- Come
posso commentare un vasto blocco di codice perl?
- Come
si cancella un package?
- Come
posso usare una variabile come nome di una variabile?
- Cosa
significa ``bad interpreter'' [``interprete non valido'', NdT]?
- AUTORE
E COPYRIGHT
perlfaq7 - Questioni Generali Sul Linguaggio Perl ($Revision: 1.16 $,
$Date: 2005/10/18 12:59:42 $)
Questa sezione tratta questioni generali sul linguaggio Perl che non
trovano posto in nessuna delle altre sezioni.
Non c'è alcuna BNF ma, se siete di animo particolarmente coraggioso, è
possibile arrivarci a tentoni con la grammatica yacc che si trova nel file
perl.y dei sorgenti. La grammatica può contare su codice molto astuto per
effettuare la divisione in token (tokenizing), preparatevi dunque ad
avventurarvi anche nel file toke.c
Citando Chaim Frenkel: ``La grammatica del Perl non può essere ridotta
alla BNF. Il lavoro di analisi sintattica che fa il perl è distribuito tra
yacc, il lexer e il gioco delle 3 carte''.
Sono specificatori di tipo, come viene spiegato in dettaglio in
perldata: $ per i valori scalari (numeri, stringhe o riferimenti)
@ per gli array
% per gli hash (array associativi)
& per le subroutine (altrimenti dette funzioni, procedure, metodi)
* per tutti i tipi di quel nome di simboli. Nella versione 4 si usavano
come puntatori, ma nei perl moderni si possono usare solo i
riferimenti
Ci sono un paio di altri simboli che è probabile incontrare che non
sono specificatori di tipo: <> sono usate per leggere un record da un filehandle.
\ ottiene un riferimento a qualcosa.
Va notato che <FILE> non è uno specificatore di tipo per i file e
nemmeno il nome dell'handle. è l'operatore <> applicato
all'handle FILE Legge una linea (o meglio, un record--consultate la voce
$/ in perlvar/$/)
dall'handle FILE se in un contesto scalare, oppure tutte le linee se in un
contesto di lista. Quando si apre, si chiude, o si esegue un'operazione
qualunque che non sia <> su un file, o anche quando si
menziona il filehandle, non si devono usare le parentesi angolari. Queste
scritture sono corrette: eof(FH), seek(FH, 0, 2)
e ``copiare da STDIN a FILE''.
Di norma, una parola non posta tra virgolette può rimanere tale, ma in
molti casi probabilmente dovrebbe essere posta tra virgolette (e deve
esserlo se use strict è attivo). La chiave di un hash che
consiste in una semplice parola (che non è il nome di una subroutine
definita) e l'operando sinistro dell'operatore =>, però,
sono trattati come se fossero tra virgolette: Questo e` come questo
------------ ---------------
$pippo{linea} $pippo{'linea'}
pluto => roba 'pluto' => roba
Il punto e virgola finale in un blocco è opzionale, così come la
virgola finale in una lista. è buono stile (vedete perlstyle)
metterli, fatta eccezione per il codice costituito da una sola linea: if ($ops) { exit 1 }
@numeri = (1, 2, 3); if ($ops) {
exit 1;
}
@linee = (
"Li` giunse Beren dal monte imponente",
"E tra le fronde e gli alberi vagabondo` disperso",
);
Un modo è quello di trattare i valori di ritorno come una lista e di
indicizzarla: $dir = (getpwnam($utente))[7];
Un'altra maniera è quella di usare undef come elemento nella parte
sinistra, come in: ($dev, $ino, undef, undef, $uid, $gid) = stat($file);
Potete anche usare uno slice di lista per selezionare solo gli elementi
che vi servono: ($dev, $ino, $uid, $gid) = ( stat($file) )[0,1,4,5];
Se state utilizzando Perl 5.6.0 o superiore, la direttiva use
warnings permette di controllare finemente quali avvertimenti
vengono generati. Consultate perllexwarn per ulteriori
dettagli. {
no warnings; # disabilita temporanemente i warning
$a = $b + $c; # questi potrebbero essere undef
}
In aggiunta, potete abilitare e disabilitare categorie di warning.
Potete togliere le categorie che volete ignorare e potete ancora ottenere
altre categorie di warning. Consultate perllexwarn per i dettagli
completi, inclusi i nomi delle categorie e gerarchie. {
no warnings 'uninitialized';
$a = $b + $c;
}
Se avete una versione più vecchia di Perl, la variabile '$^W'
(documentata in perlvar) controlla, al momento dell'esecuzione, i
warning per un blocco: {
local $^W = 0; # disabilita temporanemente i warning
$a = $b + $c; # questi potrebbero essere undef
}
È da notare che, come per tutte le variabili speciali [quelle il cui
nome è un segno di punteggiatura, NdT], non è possibile usare
my() su '$^W' ma solo local().
Un'estensione è un modo per chiamare da Perl del codice C compilato.
Leggere perlxstut è un buon modo per imparare di più sulle
estensioni.
In realtà non è vero. Tutti gli operatori del C che vengono riprodotti
in Perl hanno la stessa precedenza che hanno in C. Il problema si presenta
con gli operatori che in C non esistono, in special modo le funzioni che
conferiscono un contesto di lista a tutto quello che sta alla loro destra,
ad esempio print, chmod, exec e così via. Queste funzioni sono chiamate
``operatori di lista'' e appaiono come tali nella tabella delle precedenze
di perlop.
Un errore comune è scrivere: unlink $file || die "caos";
Esso viene interpretato come: unlink ($file || die "caos");
Per evitare questo problema, usate delle parentesi in più oppure usate
l'operatore or che ha una precedenza bassissima: (unlink $file) || die "caos";
unlink $file or die "caos";
Gli operatori ``in lingua inglese'' (and, or,
xor e not) hanno una precedenza volutamente
inferiore a quella degli operatori di lista, esattamente per le situazione
come quella menzionata sopra.
Un altro operatore con una precedenza sorprendente è l'operatore di
elevamento a potenza. Ha una precedenza superiore anche al meno unario,
facendo sì che -2**2 produca un quattro negativo anzichè
positivo. Inoltre è associativo a destra, e questo vuol dire che
2**3**2 è due elevato alla nona potenza, non otto al
quadrato.
Benché abbia la stessa precedenza che ha in C, l'operatore
?: del Perl produce un lvalue [un valore che può trovarsi a
sinistra di un operatore di assegnamento, NdT]. Questo codice assegna $x a
$a o $b, a seconda del valore di verità di $forse: ($forse ? $a : $b) = $x;
In generale, non si ``dichiara'' una struttura. Si usa un riferimento
ad un hash (di solito, anonimo). Consultate perlref e
perldsc per i dettagli. Di seguito c'è un esempio: $persona = {}; # nuovo hash anonimo
$persona->{ETA} = 24; # imposto il campo ETA a 24
$persona->{NOME} = "Nat"; # imposto il campo NOME a "Nat"
Se cercate qualcosa un po' più rigoroso, provate perltoot.
(contributed by brian d foy)
perlmod, perlmodlib, perlmodstyle spiegano i
moduli in tutti i sanguinolenti particolari. perlnewmod dà una
breve panoramica del processo insieme con un paio di suggerimenti sullo
stile.
Se avete la necessità di includere del codice C o delle librerie di
interfaccia C nei vostri moduli, avrete bisogno di h2xs. h2xs creerà la
struttura della distribuzione del modulo e gli iniziali file di
interfaccia che vi servirranno. perlxs e perlxstut
spiegano i dettagli.
Se non avete bisogno di usare del codice C, altri strumenti quali
ExtUtils::ModuleMaker e Module::Starter potrebbero aiutarvi a creare uno
scheletro di distribuzione del modulo.
Potreste anche voler dare un'occhiata al libro di Sam Tregar ``Writing
Perl Modules for CPAN'' ( http://apress.com/book/bookDisplay.html?bID=14
) che è la migliore guida pratica per la creazione di distribuzioni di
moduli.
Per una introduzione a classi e oggetti consultate la pagina del
manuale perltoot; consultate anche perlobj e
perlbot.
Potete usare la funzione tainted() del modulo
Scalar::Util, disponibile da CPAN (o inclusa con Perl a partire dalla
versione 5.8.0). Consultate inoltre perlsec/``Laundering and Detecting
Tainted Data'' [``Rendere puliti e rilevare i dati potenzialmente
dannosi'', NdT].
Le chiusure sono documentate in perlref.
Chiusura è un termine dell'informatica con un signficato
preciso ma difficile da spiegare. Le chiusure sono implementate in Perl
come subroutine anonime che conservano un riferimento persistente a
variabili lessicali non più visibili. Queste variabili lessicali,
magicamente, fanno riferimento alle variabili che erano visibili quando la
subroutine è stata definita (deep binding).
Le chiusure hanno senso in qualunque linguaggio di programmazione nel
quale il valore di ritorno di una funzione può essere esso stesso una
funzione, come in Perl. Notate che alcuni linguaggi mettono a disposizione
le funzioni anonime, ma non sono in grado di fornire chiusure effettive:
il Python, per esempio [1]. Per ulteriori informazioni sulle chiusure,
fate riferimento ad un qualunque libro sulla programmazione funzionale.
Scheme è un linguaggio che non solo supporta, ma incoraggia l'uso di
chiusure.
Ecco una classica funzione che genera una funzione: sub generatore_di_funzione_somma {
return sub { shift() + shift() };
} $funzione_somma = generatore_di_funzione_somma();
$somma = $funzione_somma->(4,5); # $sum ora e` 9.
La chiusura funziona come un template di funzione con dello spazio
lasciato libero per la personalizzazione, da riempire in seguito. La
subroutine anonima restituita da
generatore_di_funzione_somma() non è tecnicamente una
chiusura poichè non fa riferimento ad alcuna variabile lessicale non più
visibile.
Paragonate il caso precedente alla seguente funzione crea_sommatore(),
nella quale la funzione anonima che viene restituita contiene un
riferimento ad una variabile lessicale non visibile dalla funzione stessa.
Questo riferimento richiede che Perl restituisca un'opportuna chiusura,
bloccando quindi per sempre il valore che la variabile lessicale aveva
quando la funzione è stata creata. sub crea_sommatore {
my $addendo = shift;
return sub { shift() + $addendo };
} $f1 = crea_sommatore(20);
$f2 = crea_sommatore(555);
Ora &$f1($n) è sempre 20 più qualunque $n abbiate
passato, mentre &$f2($n) è sempre 555 più il valore
passato.
Le chiusure sono usate spesso per scopi meno esoterici. Ad esempio,
quando volete passare un po' di codice ad una funzione: my $linea;
timeout( 30, sub { $linea = <STDIN> } );
Se il codice fosse stato passato come stringa, '$linea =
<STDIN>', non ci sarebbe stato alcun modo, per l'ipotetica
funzione timeout(), di accedere alla variabile lessicale $line visibile
dal chiamante.
[1] NdT: questa nozione a proposito di Python non è più vera. A partire
dalla versione 2.2 si possono costruire chiusure con variabili di sola
lettura. Non conosco gli interpreti Python successivi. Per
approfondimenti: http://www.norvig.com/python-lisp.html
Il suicidio di variabile si ha quando (temporaneamente o
permanentemente) si perde il valore di una variabile. é causato da
questioni di visibilità frutto dell'interazione tra my() e
local() o con le chiusure o con variabili che sono iteratori
alias per foreach() e con argomenti di subroutine. Di solito
era facile perdere inavvertitamente il valore di una variabile in questa
modo, ora però è più difficile. Prendete questo codice: my $f = "pippo";
sub T {
while ($i++ < 3) { my $f = $f; $f .= "pluto"; print $f, "\n" }
}
T;
print "Infine $f\n";
La $f a cui è stato aggiunto ``pluto'' per tre volte dovrebbe essere
una nuova $f (my $f dovrebbe creare una nuova variabile
locale ogni volta che si compie il ciclo). Ad ogni modo non è così. Questo
era un errore, ora risolto nelle ultime versioni (testato con 5.004_05,
5.005_03 e 5.005_56).
Fatta eccezione per le espressioni regolari, dovete passare un
riferimento a questi oggetti. Consultate perlsub/``Pass by
Reference'' [``Passato per Riferimento'', NdT] per tale particolare
questione, e perlref per informazioni sui riferimenti.
Consultate il sottostante paragrafo ``Passaggio di espressioni
regolari'', per avere informazioni sul passaggio di espressioni
regolari.
- Passaggio di
variabili e funzioni
- Le variabili e le funzioni sono abbastanza facili da passare:
limitatevi a passare un riferimento ad una variabile esistente o
anonima, oppure ad una funzione:
funz( \$un_certo_scalare ); funz( \@un_certo_array );
funz( [ 1 .. 10 ] ); funz( \%un_certo_hash );
funz( { questo => 10, quello => 20 } ); funz( \&una_certa_funzione );
funz( sub { $_[0] ** $_[1] } );
- Passaggio di
filehandle
- Dal perl 5.6, potete rappresentare i filehandle con variabili
scalari che trattare come ogni altro scalare.
open my $fh, $nomefile or die "Non posso aprire $nomefile! $!";
funz( $fh ); sub funz {
my $fh_passato = shift; my $linea = <$fh>;
}
Prima del Perl 5.6, dovevate usare le notazioni *FH
oppure \*FH . Queste sono ``typeglob''--per maggiori
informazioni, consultate perldata/``Typeglobs and Filehandles''
[``Typglob e Filehandle'', NdT] e in modo particolare perlsub/``Pass
by Reference'' [``Passato per Riferimento'', NdT].
- Passaggio di
espressioni regolari
- Per passare espressioni regolari, è necessario usare una versione di
Perl sufficientemente recente da supportare il costrutto
qr//, passare stringhe e usare eval in maniera tale che
catturi le eccezioni o altrimenti essere molto, molto furbi.
Ecco un esempio che mostra come si fa a passare una stringa che deve
essere verificata con una espressione regolare, usando
qr//: sub verifica($$) {
my ($val1, $regex) = @_;
my $retval = $val1 =~ /$regex/;
return $retval;
}
$corrispondenza = verifica("old McDonald", qr/d.*D/i);
Va notato che qr// permette di usare i flag alla fine.
Quel pattern viene compilato a tempo di compilazione, benché venga
eseguito successivamente. La notazione qr// non è stata
introdotta che con la versione 5.005. In precedenza ci si doveva
avvicinare al problema in maniera molto meno intuitiva. Ecco lo stesso
esempio, nel caso non si abbia qr//: sub verifica($$) {
my ($val1, $regex) = @_;
my $retval = eval { $val1 =~ /$regex/ };
die if $@;
return $retval;
} $corrispondenza = verifica("old McDonald", q/($?i)d.*D/);
Assicuratevi di non scrivere mai cose del genere: return eval "\$val =~ /$regex/"; # SBAGLIATO
altrimenti qualcuno potrebbe insinuare comandi di shell a causa della
doppia interpolazione dell'eval e della stringa tra doppi apici. Ad
esempio: $pattern_malefico = 'pericolo ${ system("rm -rf * &") } pericolo'; eval "\$stringa =~ /$pattern_malefico/";
Chi preferisce essere molto molto furbo può consultare il volume
della O'Reilly ``Mastering Regular Expressions'', di Jeffrey Friedl. La
Build_MathMany_Function(), che si trova a pagina 273, è particolarmente
interessante. Gli estremi completi di questo testo si trovano in
perlfaq2.
- Passaggio di
metodi
- Per passare un metodo ad una subroutine, potete fare così:
chiamata_multipla(10, $un_certo_oggetto, "nome_metodo")
sub chiamata_multipla {
my ($contatore, $oggetto, $metodo) = @_;
for (my $i = 0; $i < $contatore; $i++) {
$oggetto->$metodo();
}
}
Oppure potete usare una chiusura per impacchettare l'oggetto, la
chiamata al metodo e gli argomenti: my $non_manca_niente = sub { $un_certo_oggetto->obfuscate(@args) };
funz($non_manca_niente);
sub funz {
my $codice = shift;
&$codice();
}
Potete inoltre indagare sul metodo can() della classe
UNIVERSAL (inclusa nella distribuzione standard di perl).
Come per molte cose che riguardano il Perl, c'è più di un modo per
farlo. Ciò che in altri linguaggi è una ``variabile statica'' in Perl
potrebbe essere una variabile privata ad una funzione (una variabile che è
visibile in una sola funzione, e mantiene il suo valore tra una chiamata e
l'altra), oppure una variabile privata ad un file (visibile soltanto alle
funzioni contenute nel file in cui essa è stata dichiarata).
Ecco il codice per implementare una variabile privata ad una
funzione: BEGIN {
my $contatore = 42;
sub contatore_precedente { return --$contatore }
sub contatore_successivo { return $contatore++ }
}
Ora contatore_precedente() e
contatore_successivo() condividono una variabile privata
$contatore, che è stata inizializzata durante la compilazione.
Per dichiarare una variabile privata ad un file, farete ancora uso di
my(), ponendo la dichiarazione all'inizio del file, nel blocco più
esterno. Ponete che questo sia il file Pax.pm: package Pax;
my $inizio = scalar(localtime(time())); sub cominciato { return $inizio }
Quando use Pax oppure require Pax caricano
questo modulo, la variabile sarà inizializzata. Non sarà distrutta dal
garbage collector come avviene per la maggior parte delle variabili che
non sono più visibili, perchè la funzione cominciato() se ne
occupa, ma nessun altro può ispezionarne il contenuto. Non si chiama
$Pax::inizio perchè la sua visibilità non è legata al package. La sua
visibilità coincide con il file. Potenzialmente potreste avere diversi
package nello stesso file che accedono alla stessa variabile, ma un altro
file con lo stesso package non potrebbe accederle.
Consultate perlsub/``Persistent Private Variables''
[``Variabili Private Persistenti'', NdT] per dettagli.
local($x) salvaguarda il vecchio valore della variabile
globale $x e le assegna un nuovo valore per la durata della
subroutine. Tale valore è visibile nelle funzioni chiamate da detta
subroutine. Tutto ciò viene fatto al momento dell'esecuzione, per cui
si parla di visibilità dinamica. local() opera sempre su
variabili globali, che vengono chiamate anche variabili di package o
variabili dinamiche.
my($x) definisce una nuova variabile, visibile solo nella
subroutine corrente. Ciò viene fatto al momento della compilazione, e
dunque si parla di visibilità lessicale o statica. my() opera
su variabili private, chiamate anche variabili lessicali o, in modo
improprio, variabili con visibilità statica.
Ad esempio: sub visibile {
print "il valore di var e` $var\n";
} sub dinamica {
local $var = 'locale'; # nuovo valore temporaneo per la
visibile(); # variabile $var, che resta globale
} sub lessicale {
my $var = 'privata'; # nouva variabile privata $vatr.
visible(); # (invisibile al di fuori dello scopo della subroutine)
} $var = 'globale'; visibile(); # scrive globale
dinamica(); # scrive locale
lessicale(); # scrive globale
Si noti come il valore ``privata'' non venga mai scritto. Ciò perché
tale valore di $var è visibile solo all'interno del blocco della funzione
lessicale() e non nella subroutine chiamata.
In breve, local() non produce ciò che probabilmente
pensate, ossia una variabile privata o locale. local() dà un
valore temporaneo ad una variabile globale. my() è ciò che
state cercando se desiderate ottenere delle variabili private.
Consultate anche le sezioni perlsub/``Private Variables via
my()'' [``Variabili Private tramite my()'', NdT] e
<perlsub/``Temporary Values via local()''> [``Valori Temporanei
tramite local()'', NdT] per i dolorosi dettagli.
Se conoscete il package, potete nominarlo esplicitamente, come in
$Un_Certo_Package::var. Notate che con $::var non si intende la
variabile dinamica $var nel package corrente, bensì quella nel package
``main'', come se aveste scritto $main::var. use vars '$var';
local $var = "globale";
my $var = "lessicale"; print "lessicale e` $var\n";
print "globale e` $main::var\n";
Alternativamente potete usare la direttiva del compilatore
our() per portare una variabile dinamica nello scope
lessicale corrente. require 5.006; # our() non esiste prima del 5.6
use vars '$var'; local $var = "globale";
my $var = "lessicale"; print "lessicale e` $var\n"; {
our $var;
print "globale e` $var\n";
}
Nel deep binding, le variabili lessicali che vengono nominate nelle
procedure anonime sono le stesse che si trovavano nello scope quando la
procedura è stata creata. Nello shallow binding, esse sono una qualsiasi
variabile con lo stesso nome, a cui capita di trovarsi nello scope quando
la procedura viene chiamata. Il Perl usa sempre il deep binding delle
varaibili lessicali (cioè quelle create con my()). Ad ogni modo, le
variabili dinamiche (dette anche globali, locali, o variabili package)
sono effettivamente fatte oggetto di shallow binding. Considerate questa
un'ulteriore ragione per non usarle. Guardate la risposta a Cos'è
una chiusura?
my() e local() conferiscono un contesto di
lista alla parte destra dell'assegnamento =. L'operazione di
lettura <FH>, come molti altri operatori e funzioni del Perl, è
sensibile al contesto in cui è stata chiamata, e si comporta di
conseguenza. Generalmente la funzione scalar() può essere
d'aiuto. Questa funzione non ha alcun effetto sui dati medesimi
(contrariamente alla credenza popolare) ma dice ai suoi argomenti di
seguire il comportamento che essi devono avere in un contesto scalare,
qualunque esso sia. Se la funzione non ha un comportamento scalare
definito, questa tecnica naturalmente non vi aiuterà (come nel caso di
sort()).
Per forzare un contesto scalare in questo caso specifico, ad ogni modo,
dovete semplicemente togliere le parentesi: local($pippo) = <FILE>; # SBAGLIATO
local($pippo) = scalar(<FILE>); # ok
local $pippo = <FILE>; # giusto
Probabilmente dovreste usare variabili lessicali, comunque, ma la
sostanza non cambia: my($pippo) = <FILE>; # SBAGLIATO
my $pippo = <FILE>; # giusto
Perché volete fare questo? :-)
Se si vuole sovrapporre una funzione predefinita, come open(), allora
si dovrà importare la nuova definizione da un differente modulo.
Consultate perlsub/``Overriding Built-in Functions''
[``Sovrapporre le Funzioni Predefinite'', NdT]. C'è anche un esempio in
perltoot/``Class::Template''.
Se volete sovraccaricare un operatore Perl, come + o
**, allora troverete conveniente usare la direttiva use
overload, documentata in overload.
Se state parlando di oscure chiamate a metodi in classi genitore,
consultate perltoot/``Overridden Methods'' [``Metodi
Sovrapposti'', NdT].
Quando chiamate una funzione come &pippo, permettete
che la funzione acceda ai valori correnti contenuti in @_ ed evitate di
prendere in considerazione i prototipi. La funzione non otterrà un @_
vuoto--otterrà il vostro! [l'array del chiamante, NdT] Benché strettamente
parlando non si possa dire un bug (è documentato in questo modo in
perlsub), nella maggior parte dei casi sarebbe difficile considerarlo una
caratteristica.
Quando chiamate una funzione come &pippo(), allora
ottenete un nuovo @_, ma l'uso dei prototipi viene anche in questo caso
aggirato.
Normalmente le funzioni si chiamano usando pippo(). Potete
omettere le parentesi solo se la funzione è già nota al compilatore perché
ne ha già visto la definizione (usando use e non
require), o grazie ad un riferimento in avanti, oppure grazie
ad una dichiarazione use subs. Anche in questo caso otterrete un nuovo @_
senza nessuno dei vecchi valori che spunta là dove non dovrebbe.
Viene spiegato più approfonditamente in perlsyn. In sintesi,
non c'è un'istruzione case ufficiale a causa della varietà di test che
sono possibili in Perl (confronto numerico, confronto tra stringhe,
confronto tra glob, pattern matching, operatori di confronto con più
significati, ...). Larry non è riuscito a decidere quale fosse il modo
migliore per farlo, e quindi lo ha lasciato da parte, benché sia nella
lista dei desideri già dalla prima versione di Perl.
A partire da Perl 5.8 per avere switch e case si deve usare
l'estensione Switch: use Switch;
e si avranno switch e case. Non è veloce quanto potrebbe esserlo,
poiché non è realmente parte del linguaggio (è fatto usando i source
filter) ma è disponibile, ed è molto flessibile.
Se però si vuole usare Perl puro, la risposta generale è scrivere un
construtto come questo: for ( $variabile_da_verificare ) {
if (/pat1/) { } # fai qualcosa
elsif (/pat2/) { } # fai qualcos'altro
elsif (/pat3/) { } # fai qualcos'altro
else { } # default
}
Ecco un semplice esempio di switch basato su pattern matching, questa
volta incolonnato in maniera tale che assomigli maggiormente ad una
istruzione switch. Realizzeremo un costrutto condizionale a più vie basato
sul tipo di riferimento memorizzato in $ref: SWITCH: for (ref $ref) { /^$/ && die "non e` un riferimento"; /SCALAR/ && do {
print_scalar($$ref);
last SWITCH;
}; /ARRAY/ && do {
print_array(@$ref);
last SWITCH;
}; /HASH/ && do {
print_hash(%$ref);
last SWITCH;
}; /CODE/ && do {
warn "non posso stampare un riferimento a funzione";
last SWITCH;
}; # DEFAULT warn "Tipo definito dall'utente, tralasciato"; }
Consultate perlsyn/``Basic BLOCKs and Switch Statements
[''BLOCK di Base e Istruzioni Switch``, NdT] per trovare molti altri
esempi in questo stile.
A volte potreste dover modificare la posizione della costante e della
variabile. Ad esempio, poniamo che vogliate sapere quale tra tante
risposte avete ricevuto, ma in maniera non dipendete dalle
maiuscole/minuscole, e permettendo abbreviazioni. Potreste usare la
seguente tecnica se le stringhe cominciano tutte con caratteri diversi, o
se volete ordinare le corrispondenze in maniera tale che una abbia la
precedenza sull'altra, così come in questo caso SEND ha la
precedenza su STOP: chomp($answer = <>);
if ("SEND" =~ /^Q$answer/i) { print "L'azione e` send\n" }
elsif ("STOP" =~ /^Q$answer/i) { print "L'azione e` stop\n" }
elsif ("ABORT" =~ /^Q$answer/i) { print "L'azione e` abort\n" }
elsif ("LIST" =~ /^Q$answer/i) { print "L'azione e` list\n" }
elsif ("EDIT" =~ /^Q$answer/i) { print "L'azione e` edit\n" }
Un approccio del tutto differente consiste nel creare un hash di
riferimenti a funzione: my %commands = (
"felice" => \&gioia,
"triste" => \&grigiore,
"finito" => sub { die "Ci vediamo!" },
"matto" => \&rabbia,
); print "Come stai? ";
chomp($string = <STDIN>);
if ($commands{$string}) {
$commands{$string}->();
} else {
print "Non esiste questo comando: $string\n";
}
Il metodo AUTOLOAD, discusso in perlsub/``Autoloading'' e in
perltoot/``AUTOLOAD: Proxy Methods'' [``AUTOLOAD: Metodi Proxy'',
NdT], vi consente di catturare le chiamate a funzioni e metodi
indefiniti.
Quando invece si tratta di variabili indefinite che genererebbero un
avvertimento in presenza di use warnings, potete promuovere
l'avvertimento in un errore. use warnings FATAL => qw(uninitialized);
Alcune ragioni possibili: il meccanismo dell'ereditarietà si è confuso,
avete scritto male il nome del metodo, oppure l'oggetto è del tipo
sbagliato. Fate riferimento a perltoot per dettagli su ciascuno
dei casi menzionati. Potreste inoltre usare print
ref($object) per sapere qual è la classe nella quale
$oject è stato sottoposto alla funzione bless().
Un'altra possibile fonte di problemi è l'uso della sintassi indiretta
per gli oggetti (ad esempio trova Guru "Samy") sul nome di
una classe prima che Perl abbia visto che il relativo package esiste. È
più saggio assicurarsi che tutti i vostri package siano definiti, prima di
usarli. Verrà fatto se usate l'istruzione use anziché
require. Altrimenti, assicuratevi di usare la ``notazione con
freccia'' (ad esempio Guru->trova( "Samy" )). La notazione
per gli oggetti è spiegata in perlobj.
Assicuratevi di leggere perlmod a proposito della creazione
dei moduli, e perlobj/``Method invocation'' [``Invocazione di
Metodi'', NdT] a proposito dei pericoli degli oggetti indiretti.
In un programma generico, per conoscere il package dell'unità di
compilazione corrente potete fare in questo modo: my $nome_package = __PACKAGE__;
Ma se si tratta di un metodo e volete stampare un messaggio d'errore
che menzioni il tipo di oggetto sul quale è stato invocato (che non è
necessariamente quello in cui il metodo è stato compilato): sub metodo {
my $self = shift;
my $class = ref($self) || $self;
warn "Sono stato chiamato da un oggetto $class";
}
Potete usare il POD incorporato nel codice per mettere quest'ultimo da
parte. Racchiudete i blocchi che volete commentare tra etichette POD. La
direttiva <=begin> contrassegna una sezione per uno specifico
formattatore. Usate il formato comment, che nessun
formattatore dovrebbe pretendere di saper capire (per scelta).
Contrassegnate la fine del blocco con <=end>. # il programma e` qui =begin comment Tutte queste cose qui saranno ignorate
da tutti =end comment =cut # il programma continua
Le direttive pod non possono andare proprio dappertutto. Dovete
inserire una direttiva pod dove il parser si aspetta una nuova istruzione,
non semplicemente nel mezzo di una espressione o di qualche altra
produzione grammaticale.
Consultate perlpod per maggiori dettagli.
Usate questo codice, fornito da Mark-Jason Dominus: sub scrub_package {
no strict 'refs';
my $pack = shift;
die "Non si dovrebbe eliminare il package main"
if $pack eq "" || $pack eq "main";
my $stash = *{$pack . '::'}{HASH};
my $nome;
foreach $name (keys %$stash) {
my $nomecompleto = $pack . '::' . $nome;
# Elimino tutto con quel nome
undef $$nomecompleto;
undef @$nomecompleto;
undef %$nomecompleto;
undef &$nomecompleto;
undef *$nomecompleto;
}
}
Oppure, se state usando una versione recente di Perl, al suo posto
potete semplicemente usare la funzione Symbol::delete_package() .
I principianti spesso ritengono di voler avere una variabile che a sua
volta contiene il nome di una variabile. $fred = 23;
$nome_variabile = "fred";
++$$nome_variabile; # $fred adesso vale 24
A volte funziona, ma è un'idea molto sbagliata, per due
ragioni.
La prima ragione è che funziona solo con variabili globali.
Questo vuol dire che se nell'esempio precedente $fred fosse una variabile
lessicale creata con my(), il codice non funzionerebbe per niente:
accedereste accidentalmente alla globale, saltando a piè pari la variabile
lessicale privata. Le variabili globali non vanno bene perché possono
facilmente dar luogo a conflitti accidentali, e in generale rendono il
codice confuso e non scalabile.
I riferimenti simbolici sono proibiti quando la direttiva use
strict è attiva. Non sono veri riferimenti e di conseguenza non
sono soggetti al conteggio dei riferimenti e alla garbage collection.
L'altra ragione per cui usare una variabile per mantenere il nome di
un'altra variabile è una cattiva idea è che la questione spesso scaturisce
da una mancanza di comprensione delle strutture dati Perl, in particolare
degli hash. Se usate i riferimenti simbolici di fatto state usando l'hash
che contiene la tabella dei simboli del package come %main::)
anziché un hash definito dall'utente. La soluzione è usare un hash vostro
oppure un riferimento vero e proprio. $VARIABILI_UTENTE{"fred"} = 23;
$nome_variabile = "fred";
$VARIABILI_UTENTE{ $nome_variabile }++; # non $$nome_variabile++
Stiamo usando l'hash %VARIABILI_UTENTE anziché i riferimenti simbolici.
A volte capita durante la lettura di stringhe inserite dall'utente che
contengono riferimenti a variabili che si vogliono espandere con i valori
delle variabili del programma. Anche questa è una cattiva idea, poiché
confonde gli spazi dei nomi indirizzabili dal programma e dall'utente.
Anzichè leggere una stringa ed espanderla con gli effettivi contenuti
delle variabili proprie del programma: $str = 'qui ci sono $fred e $barney';
$str =~ s/(\$\w+)/$1/eeg; # c'e` bisogno di un doppio eval
sarebbe meglio mantenere un hash come %VARIABILI_UTENTE e far sì che i
riferimenti puntino in effetti ai contenuti di questo hash: $str =~ s/\$(\w+)/$VARIABILI_UTENTE{$1}/g; # nessun /e
È più veloce, più pulito e più sicuro dell'approccio precedente.
Naturalmente, non c'è bisogno del simbolo del dollaro. Potete usare uno
schema personale per rendere le cose meno confuse, come ad esempio dei
simboli di percentuale usati a mo' di parentesi, ecc. $str = 'qui ci sono %fred% e %barney%';
$str =~ s/%(\w+)%/$VARIABILI_UTENTE{$1}/g; # nessun /e
Un'altra ragione per cui le persone a volte pensano di volere una
variabile che contiene il nome di una variabile è che non sanno come
costruire opportune strutture usando gli hash. Ad esempio, diciamo che in
un programma si vogliono due hash: %fred e %barney e si vuole adoperare un
altro scalare per fare riferimento ad esse per nome. $nome = "fred";
$$nome{MOGLIE} = "wilma"; # imposta %fred $nome = "barney";
$$nome{MOGLIE} = "betty"; # imposta %barney
C'è ancora un riferimento simbolico, ed è ancora afflitto dai problemi
elencati sopra. Sarebbe di gran lungo meglio scrivere: $gente{"fred"}{MOGLIE} = "wilma";
$gente{"barney"}{MOGLIE} = "betty";
E usate solo un hash a più livelli.
Le uniche occasioni in cui dovete assolutamente usare i
riferimenti simbolici sono quelle in cui ci si deve riferire alla tabella
dei simboli. Potrebbe essere perché si ha a che fare con qualcosa per cui
non è possibile avere un riferimento, ad esempio il nome di un formato.
Questa pratica potrebbe essere importante anche per le chiamate ai metodi,
visto che per essere risolte, passano attraverso la tabella dei
simboli.
In questi casi, dovreste disattivare strict 'refs'
temporaneamente in maniera tale da poter trafficare con la tabella dei
simboli. Ad esempio: @colori = qw(rosso blu verde giallo arancione porpora viola);
for my $nome (@colori) {
no strict 'refs'; # chiudi un occhio per tutto il blocco
*$nome = sub { "<FONT COLOR='$nome'>@_</FONT>" };
}
Tutte queste funzioni (rosso(), blu(), verde(), ecc.) sembrano
separate, ma il codice della chiusura è stato compilato, in realtà, una
volta sola.
Quindi, a volte potreste voler usare dei riferimenti simbolici per
manipolare direttamente la tabella dei simboli. Non importa se si tratta
di format, handle o subroutine, poiché sono sempre globali -- non potete
usare my() su di loro. Per gli scalari, gli array e gli hash,
però -- e di solito per le subroutine --, probabilmente volete usare solo
hard reference.
(contributed by brian d foy)
Il messaggio ``bad interpreter'' deriva dalla shell, non dal perl. Il
messaggio vero e proprio può variare a seconda della vostra piattaforma,
shell e impostazione del locale.
Se vedete ``bad interpreter - no such file or directory'' [``interprete
non valido - file o directory non presente'', NdT], la prima linea nel
vostro script perl (la ``shebang'') non contiene il corretto percorso al
perl (oppure qualsiasi altro programma in grado di eseguire degli script).
Talvota questo avviene quando spostate lo script da una macchina ad
un'altra e ogni macchina ha un differente percorso al perl---per esempio
/usr/bin/perl piuttosto che /usr/local/bin/perl per esempio. Potrebbe
anche indicare che la macchina sorgente abbia terminatori di linea del
tipo CRLF e la macchina destinazione abbia solo i LF: la shell cerca di
trovare /usr/bin/perl<CR>, ma non ci riesce.
Se vedete ``bad interpreter: Permission denied'' [interprete non
valido: Permesso negato``, NdT], avete bisogno di rendere eseguibile il
vostro script.
In entrambi i casi, dovreste essere ancora in grado di eseguire gli
script, esplicitamente con perl: % perl script.pl
Se ottenete un messaggio come ``perl: command not found'' [``perl:
comando non trovato'', NdT], perl non è nel vostro PATH [percorso, NdT],
che potrebbe anche significare che la posizione del perl non è dove vi
aspettate, dunque sarà necessario modificare la vostra shebang.
Copyright (c) 1997-2005 Tom Christiansen, Nathan Torkington e altri
autori menzionati. Tutti i diritti riservati.
La traduzione in italiano è a cura del progetto pod2it ( http://pod2it.sourceforge.net/
)
Questa documentazione è libera; potete ridistribuirla e/o modificarla
secondo gli stessi termini applicati al Perl.
Indipendentemente dalle modalità di distribuzione, tutti gli esempi di
codice in questo file sono rilasciati al pubblico demanio. Potete, e siete
incoraggiati a farlo, utilizzare il presente codice o qualunque forma
derivata da esso nei vostri programmi per divertimento o per profitto. Un
semplice commento nel codice che dia riconoscimento alle FAQ sarebbe
cortese ma non è obbligatorio.
Mon Oct 24 04:01:49 2005 |