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.
|