- NOME
- DESCRIZIONE
- È possibile ottenere una BNF/yacc/RE del linguaggio Perl?
- 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
- TRADUZIONE
perlfaq7 - Questioni Generali Sul Linguaggio Perl ($Revision: 1.19 $, $Date: 2009-01-26 17:06:25 $)
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.
(contributo di 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
Questo problema è stato risolto nel perl 5.004_05, dunque prevenirlo significa
aggiornare la vostra versione di perl. ;)
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";
Se state avendo a che fare con il suicidio di variabile, quel my $f nella subroutine
non tira su una nuova copia di $f , il cui valore è pippo . L'output
mostra che all'interno della subroutine, il valore di $f oltrepassa i limiti
quando non dovrebbe, come in questo output:
pippopluto
pippoplutopluto
pippoplutoplutopluto
Infine pippo
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. L'output che ci si aspetta è:
pippopluto
pippopluto
pippopluto
Infine pippo
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).
(contributo di brian d foy)
Perl non ha le variabili ``statiche'', alle quali si può avere accesso solo
dalla funzione nella quale sono dichiarate. Però potete ottenere lo
stesso effetto con le variabili lessicali.
Potete simulare una variabile statica usando una variabile lessicale che
va al di fuori dello scope. In questo esempio, si definisce la subroutine contatore
che usa la variabile lessicale $contatore . Dato che lo inserite in un blocco BEGIN,
$contatore è definito a tempo di compilazione, ma esso va anche fuori dallo
scope alla fine del blocco BEGIN. Il blocco BEGIN assicura anche che la subroutine e
il valore che essa usa sia definito a tempo di compilazione di modo che la subroutine
sia pronta all'uso proprio come ogni altra subroutine, e si possa inserire questo codice
nella stessa posizione come per le altre subroutine nel testo del programma (ovvero, di
solito, alla fine del codice). La subroutine contatore ha ancora un riferimento ai dati e
questa è la sola maniera che avete per accedere al valore (ed ogni volta che lo
fate, ne incrementate il valore). I dati nella porzione di memoria definita da $contatore
è privata per contatore .
BEGIN {
my $contatore = 1;
sub contatore { $contatore++ }
}
my $partenza = contatore();
.... # codice che chiama contatore();
my $fine = contatore();
Nell'esempio precedente, avete creato una variabile privata per una funzione
perch<eacute> solo una funzione si è il suo riferimento. Potreste definire
funzioni multiple mentre la variabile è nello scope, ed ogni funzione
può condividere la variabile ``privata''. Non è davvero ``statica'' perché
potete accedervi dal di fuori della funzione finché la variabile lessicale è
nello scope e potete anche creare riferimenti ad essa. In questo esempio, incrementa_contatore e
restituisci_contatore condividono la variabile. Una funzione incrementa il valore e l'altra
semplicemente lo restituisce. Entrambe possono accedere a $contatore e visto che esso è
andato al di fuori dello scope, non c'è altro modo per accedervi.
BEGIN {
my $contatore = 1;
sub incrementa_contatore { $contatore++ }
sub restituisci_contatore { $contatore }
}
Per dichiarare una variabile privata per un file, potete usare ancora una
variabile lessicale. Un file è anche uno scope, dunque una variabile
lessicale definita nel file non può essere vista da qualsiasi altro file.
Consultate perlsub/``Persistent Private Variables'' [``Variabili Private Persistenti'', NdT]
per maggiori informazioni. La discussione sulle chiusure in perlref potrebbe aiutarvi
anche se non abbiamo usato le subroutine anonime in questa risposta.
Consultate perlsub/``Persistent Private Variables'' per i 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.
(contributo di 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-2006 Tom Christiansen, Nathan Torkington e altri autori menzionati.
Tutti i diritti riservati.
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 dominio. 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.
La versione su cui si basa questa traduzione è ottenibile con:
perl -MPOD2::IT -e print_pod perlfaq7
Per maggiori informazioni sul progetto di traduzione in italiano si veda
http://pod2it.sourceforge.net/ .
Traduzione a cura di Michele Beltrame.
Revisione a cura di dree.
Mon Jun 11 22:02:15 2012
|