NOME |
perldata - Tipi di dato in Perl
Perl ha tre tipi di dati incorporati: scalari, array di scalari e array associativi di scalari, meglio noti come ``hash''. Uno scalare può essere costituito da una singola stringa (di qualsiasi dimensione, limitata solo dalla memoria a disposizione), da un numero o da un riferimento a qualcosa (il che viene discusso in the perlref manpage). I normali array sono liste ordinate di scalari indicizzate con un numero intero, partendo da 0. Le hash sono collezioni non ordinate di valori scalari indicizzate attraverso una stringa associata ad essi, detta chiave.
Di solito ci si riferisce ai valori o per nome, o attraverso un
riferimento con nome. Il primo carattere del nome vi dice a che tipo
di struttura dati si riferisce; il resto del nome indica il particolare
valore. Di solito questo nome è un singolo identificatore, ossia
una stringa che comincia con una lettera o un underscore [il trattino
messo in basso ``_'', N.d.T.], e prosegue con lettere, underscore e
cifre numeriche. In alcuni casi potrebbe essere una concatenazione di
identificatori, separati da ::
(o dal più arcaico '
); tutti questi
identificatori, eccetto l'ultimo, sono interpretati come nomi di
package [pacchetto, ma utilizziamo la parola inglese poiché coincide
con la parola chiave di Perl, N.d.T.], per individuare lo spazio dei nomi
nei quali andare a cercare l'identificatore finale (consultate anche
Packages in the perlmod manpage per maggiori dettagli). È possibile
sostituire, al posto di un semplice identificatore, un'espressione che
produca dinamicamente un riferimento al valore. Il tutto viene descritto
con maggior dettaglio più avanti ed in the perlref manpage.
Perl ha anche le sue variabili incorporate i cui nomi non seguono
queste regole. Queste variabili hanno nomi strani, per cui non c'è il
rischio che vadano accidentalmente a collidere con una delle vostre
variabili. Le stringhe che corrispondono alle parti fra parentesi di
un'espressione regolare sono salvate con nomi che contengono solo
cifre numeriche dopo il carattere $
(consulate the perlop manpage e the perlre manpage).
In aggiunta, parecchie variabili speciali che danno accesso nella
sezione più interna di Perl hanno nomi che contengono caratteri di
punteggiatura o di controllo. Tutte queste variabili sono documentate
in the perlvar manpage.
I valori scalari hanno sempre nomi con $
, anche quando si
riferiscono ad uno scalare che fa parte di un array o di una hash. Il
simbolo $
lavora, semanticamente, come l'articolo determinativo ``il'',
nel senso che denota il fatto che ci si aspetta un singolo valore.
$giorni # Il semplice valore scalare "giorni" $giorni[28] # Il ventinovesimo elemento dell'array @giorni $giorni{'Feb'} # Il valore 'Feb' dall'hash %giorni $#giorni # L'ultimo indice dell'array @giorni
Interi array (e slice [porzioni, N.d.T.] di array ed hash) sono
indicati con @
, che ha una funzione molto simile alle parole
italiane ``questi'' o ``quelli'', nel senso che indica che ci si aspettano
più valori.
@giorni # ($giorni[0], $giorni[1], ..., $giorni[n]) @giorni[3, 4, 5] # corrisponde a ($giorni[3], $giorni[4], $giorni[5]) @giorni{'a', 'c'} # corrisponde a ($giorni{'a'}, $giorni{'c'})
Le hash intere sono denotate da %
:
%giorni # ($chiave1, $valore1, $chiave2, $valore2, ...)
In aggiunta, le subroutine hanno nomi che iniziano con &
,
sebbene ciò sia opzionale quando non dia adito ad ambiguità, esattamente
come la parola proprio è ridondante in italiano [quando usata
come rafforzativo, ad esempio in ``sono proprio felice'', N.d.T.].
Gli elementi della
tabella dei simboli possono essere richiamati con un *
iniziale, ma
questo non vi interessa ancora (o probabilmente non vi interesserà mai :-).
Ciascun tipo di variabile ha il proprio spazio dei nomi, così come
parecchi identificativi che non sono relativi a variabili. Ciò significa
che potete, senza temere di creare collisioni, utilizzare lo stesso
identico nome per una variabile scalare, per un array e per una hash e,
per quanto possa contare, per un filehandle, per un handle di
directory, per il nome di una sub, di un formato o anche di
un'etichetta. Ciò implica che $tizio
e @tizio
sono due variabili
distinte, ed anche che $caio[1]
è parte di @caio
ma non di $caio
.
Potrebbe sembrarvi un po' strano ma va bene così, perché è strano.
A causa del fatto che i nomi delle variabili iniziano sempre
con $
, @
o %
, le parole ``riservate'' non sono di fatto
proibite rispetto ai nomi di variabile. Esse sono riservate
rispetto ad etichette e filehandle, comunque, che non hanno
un carattere iniziale distintivo speciale. Non potete avere un
filehandle chiamato ``log'', ad esempio. Suggerimento: potete
sempre utilizzare open(LOG, 'logfile)
piuttosto che
open(log, 'logfile')
. Utilizzare filehandle tutti maiuscoli
migliora anche la leggibilità e vi protegge da possibili conflitti
con parole riservate introdotte in futuro. La differenza fra
maiuscole e minuscole è importante -- ``SEMPRONIO'', ``Sempronio'' e
``sempronio'' sono tutti nomi differenti. I nomi che iniziano con una
lettera o un underscore possono anche contenere cifre numeriche
e underscore.
È possibile rimpiazzare questi nomi alfanumerici con un'espressione che restituisce un riferimento al tipo appropriato. Per una descrizione vedete the perlref manpage.
I nomi che iniziano con una cifra numerica possono contenere solo
altre cifre numeriche. I nomi che non cominciano con una lettera,
underscore, cifra numerica o con un accento circonflesso (ossia,
un carattere di controllo) sono limitati ad un singolo carattere,
ad esempio $%
o $$
. (La maggior parte di questi nomi con
un singolo carattere hanno significati predefiniti in Perl. Ad
esempio, $$
è l'identificativo del processo corrente).
L'interpretazione di operazioni e valori in Perl a volte dipende dai requisiti del contesto intorno all'operazione o al valore. Ci sono due contesti principali: lista e scalare. Alcune operazioni restituiscono liste in contesti che chiedono liste, e valori scalari altrimenti. Se questo vale per un'operazione, questo fatto sarà menzionato nella relativa documentazione. In altre parole, Perl sovraccarica alcune operazioni basandosi sul fatto che ci si aspetti un valore singolare o plurale. Alcune parole in italiano si comportano allo stesso modo, ad esempio ``pesce'' [che può essere riferito ad una molteplicità - come in ``oggi mangiamo pesce'' - o al singolo elemento - come in ``Ho preso un pesce solo oggi''].
In modo del tutto reciproco, un'operazione fornisce un contesto scalare o lista a ciascuno dei suoi argomenti. Ad esempio, se scrivete
int( <STDIN> )
l'operazione ``intero'' fornisce un contesto scalare all'operatore diamante <>, che dunque reagisce leggendo una singola riga da STDIN restituendola all'operazione ``intero'', che troverà infine il valore intero di quella linea e lo restituirà a sua volta. Se, d'altra parte, scrivete
sort( <STDIN> )
allora l'operazione sort
fornisce un contesto lista a <>, che
procederà a leggere ogni linea disponibile fino alla fine del file,
restituendola a sort
. Questa funzione, a sua volta, ordinerà tale
lista di righe e la restituirà come lista, qualsiasi sia il contesto
in cui è stata chiamata.
L'assegnazione è un pochino speciale, nel senso che utilizza il suo argomento a sinistra per determinare il contesto dell'argomento di destra. L'assegnazione ad uno scalare valuta la parte a destra in contesto scalare, mentre l'assegnazione ad un array o ad una hash fa sì che la parte destra sia valutata in contesto lista. Anche l'assegnazione ad una lista (o slice, che è comunque una lista) valutano la parte destra in contesto lista.
Quando utilizzate la direttiva use warnings
o l'opzione a linea
di comando -w, potreste vedere degli avvertimenti riguardo l'uso
inutile [``useless use'' nel messaggio, N.d.T.] di costanti o funzioni
in ``contesto void'' [letteralmente ``vuoto'', ma si preferisce lasciare
l'originale in inglese viste anche le similitudini con il tipo void
disponibile in C. N.d.T.]. Il contesto void significa semplicemente che il
valore è stato gettato via, come in un'istruzione che contiene solo
"fred";
o getpwuid(0);
. Conta comunque come contesto scalare
per funzioni che fanno distinzione fra l'essere chiamate o meno
in contesto lista.
Le funzioni definite da utente possono scegliere di comportarsi differentemente se sono chiamate in contesto void, scalare o lista. La maggior parte delle funzioni non avranno però bisogno di preoccuparsene, poiché sia scalari che liste sono automaticamente interpolati in liste. Consultate wantarray in the perlfunc manpage per sapere come fare a stabilire dinamicamente in quale contesto è stata chiamata la vostra funzione.
Tutti i dati in Perl sono scalari, array di scalari, o hash di scalari. Uno scalare può contenere un singolo valore di tre tipi differenti: un numero, una stringa o un riferimento. In generale, la conversione da una forma all'altra è trasparente all'utente. Sebbene uno scalare non possa contenere valori multipli, può contenere un riferimento ad un array o ad una hash che, a loro volta, possono contenere valori multipli.
Gli scalari non devono essere per forza una cosa o l'altra. Non c'è nessun posto dove dichiarare una variabile scalare come ``stringa'', ``numero'', ``riferimento'' o qualsiasi altra cosa. A causa della conversione automatica, le operazini che restituiscono scalari non hanno bisogno di preoccuparsi (ed infatti non lo fanno) se il chiamante sta aspettando una stringa, un numero o un riferimento. Perl è un linguaggio contestualmente polimorfico i cui scalari possono essere stringhe, numeri o riferimenti (il che include gli oggetti). Sebbene stringhe e numeri siano considerati più o meno la stessa cosa per quasi tutti gli scopi, i riferimenti sono puntatori a tipizzazione forte e non modificabili, con un meccanismo di conteggio dei riferimenti [reference-counting, N.d.T.] e chiamata dei distruttori.
Un valore scalare è considerato VERO in senso booleano se non è la stringa nulla o il numero 0 (ovvero il suo equivalente stringa ``0''). Il contesto booleano è solo una variante speciale del contesto scalare, dove non viene mai effettuata alcuna conversione verso una stringa o un numero.
Ci sono in realtà due varietà di stringhe nulle (a volte
dette stringhe ``vuote''), una definita ed una indefinita. La versione
definita è solo una stringa che ha lunghezza nulla, come ""
.
La versione indefinita è quel valore che indica che non c'è un vero
valore per qualcosa, come quando c'è stato un errore, o alla fine
di un file, o quando vi riferite a variabili non inizializzate sia
scalari che parti di array o hash. Sebbene nelle version più datate
di Perl uno scalare non definito potesse diventare definito al suo
primo utilizzo in un posto dove era atteso un valore definito,
questo non si ha più eccetto per rari casi di autovivificazione
descritti in the perlref manpage. Potete utilizzare l'operatore defined()
per determinare se un valore scalare è definito (la cosa non
ha significato su array o hash), e l'operatore undef()
per
produrre un valore indefinito.
Per stabilire se una data stringa è un valore numerico valido e non nullo, è di solito sufficiente confrontarlo sia con lo 0 numerico che con lo ``0'' lessicale (sebbene questo causerà un po' di rumore se gli avvertimenti sono attivati). Ciò segue dal fatto che le stringhe che non sono numeri contano come 0, tale e quale che in awk:
if ($str == 0 && $str ne "0") { warn "Non sembra essere un numero"; }
Questo metodo potrebbe essere il migliore, perché altrimenti non
considererete notazioni IEEE come NaN
o Infinity
in maniera
appropriata. In altre occasioni potreste preferire determinare se
una stringa può essere utilizzata numericamente chiamando la funzione
POSIX::strtod()
, o controllandola con un'espressione regolare
(come documentato in the perlre manpage):
warn "ha caratteri non numerici" if /\D/; warn "non un numero naturale" unless /^\d+$/; # rifiuta -3 warn "non un numero intero" unless /^-?\d+$/; # rifiuta +3 warn "non an numero intero" unless /^[+-]?\d+$/; warn "non un numero decimale" unless /^-?\d+\.?\d*$/; # rifiuta .2 warn "non un numero decimale" unless /^-?(?:\d+(?:\.\d*)?|\.\d+)$/; warn "non un float C" unless /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/;
La lunghezza di un array è un valore scalare. Potete trovare la
lunghezza dell'array utilizzando $#giorni
, come in csh; ad
ogni modo, questa non è la lunghezza dell'array, ma l'indice
corrispondente all'ultimo elemento, che è un valore differente
poiché usualmente c'è un valore di indice 0. Assegnare a $#giorni
cambia la lunghezza dell'array; accorciare un array in questo modo
distrugge i valori tagliati fuori, ed una successiva operazione
di allungamento non ripristinerà i valori che si trovavano in
quegli elementi. (Era così in Perl 4, ma questo comportamento è
stato cambiato per essere sicuri che i distruttori venissero
chiamati quando ci si attendeva che lo fossero).
Potete anche guadagnare qualche minuscola frazione di efficienza
allungando un array in anticipo quando sapete che diventerà grande.
Potete estendere un array anche assengando un valore ad un elemento
che si trova fuori dal bordo estremo dell'array. Potete troncare un
array assegandogli la lista nulla ()
. Le seguenti istruzioni
sono equivalenti:
@qualcosa = (); $#qualcosa = -1;
Se valutate un array in contesto scalare viene restituita la lunghezza dell'array. (Osservate che questo non è vero nel caso delle liste, che restituiscono l'ultimo valore, analogamente all'operatore virgola del C. Non è vero neanche nel caso delle funzioni incorporate, che restituiscono quello che sembra loro più corretto). La seguente affermazione è sempre vera:
scalar(@qualcosa) == $#qualcosa - $[ + 1;
La versione 5 di Perl ha cambiato il significato di $[
: i file
che non impostano il valore di $[
non hanno più bisogno di
preoccuparsi se un altro file ne ha alterato il valore. (In altre
parole, l'utilizzo di $[
è scoraggiato). In generale potete
dunque assumere che
scalar(@qualcosa) == $#qualcosa + 1;
Alcuni programmatori scelgono di utilizzare una conversione esplicita per non lasciare spazio a dubbi:
$numero_di_elementi = scalar(@qualcosa);
Se valutate una hash in contesto scalare viene restituito un
valore FALSO se l'hash è vuota. Se esiste anche una sola coppia
chiave/valore, viene restituito un valore VERO; più precisamente,
il valore restituito è una stringa costituita dal numero di
caselle utilizzate ed il numero di caselle allocate, separate
da una sbarretta obliqua. Questo può essere utile solamente se
volete stabilire se l'algoritmo di hashing interno di Perl si
sta comportando bene o meno sul vostro insieme di dati. Ad
esempio, voi inserite 10.000 elementi in una hash, ma
valutando %HASH in contesto scalare restituisce "1/16"
che
significa che solo una di sedici caselle è stata utilizzata, e
presumibilmente contiene tutti e 10.000 gli elementi. Si suppone
che questo non accada.
Potete prenotare spazio per una hash con un'assegnazione alla
funzione keys()
. Questa operazione arrotonda il numero di
caselle allocate alla potenza di 2 immediatamente superiore:
keys(%utenti) = 1000; # alloca 1024 caselle
I letterali numerici possono essere specificati in uno qualsiasi dei seguenti formati interi o a virgola mobile:
12345 12345.67 .23E-10 # un numero piuttosto piccolo 3.14_15_92 # un numero molto importante 4_294_967_296 # l'underscore aumenta la leggibilita` 0xff # esadecimale 0xdead_beef # piu` esadecimale 0377 # ottale (solo cifre, inizia con 0) 0b011011 # binario
È consentito utilizzare underscore fra le cifre nei letterali numerici per leggibilità. Potreste, ad esempio, raggruppare le cifre binarie a tre a tre (come nell'impostazione del modo dei file in stile Unix, ad esempio 0b110_100_100), o a quattro a quattro (per rappresentare metà di ottetti, come in 0b1010_0110), o in altri gruppi.
Le stringhe letterali sono usualmente delimitate da un apice
singolo o doppio. Entrambi lavorano molto similmente alle virgolette
nelle shell standard Unix: le stringhe letterali con virgolette
doppie sono soggette a sostituzione di backslash e di
variabile; le stringhe con virgolette semplici non lo sono, invece,
(con le uniche eccezioni di \'
e \\
). Le usuali regole
in stile C per il backslash si applicano per generare caratteri
speciali come a-capo, tabulazioni, ecc., così come forme più esotiche.
Consultate Quote and Quote-like Operators in the perlop manpage per averne
una lista.
Le rappresentazioni esadecimali, ottali o binarie in stringhe letterali
non sono automaticamente convertite alla loro rappresentazione
intera. Le funzioni hex()
e oct()
si occupano di queste
conversioni per conto vostro; consultate hex in the perlfunc manpage e
oct in the perlfunc manpage per maggiori ragguagli.
Potete anche includere a-capo direttamente nelle stringhe, ossia
queste possono terminare in una riga differente da quella in cui
iniziano. Questa è una caratteristica apprezzabile, ma se vi
dimenticate le virgolette di chiusura l'errore non verrà segnalato
finché Perl non trova un'altra riga contenente la virgoletta stessa,
che potrebbe essere molto più in là nello script. La sostituzione di
variabili all'interno delle stringhe è limitato alle variabili
scalari, agli array ed alle slice
di array o di hash. (In altre
parole, i nomi che cominciano con $
o @
, seguiti da
un'espressione fra parentesi facoltativa). Il seguente frammento
di codice stampa ``Il prezzo ammonta a $100'':
$Prezzo = '$100'; # non interpolato print "Il prezzo ammonta a $Prezzo.\n"; # interpolato
Non esiste doppia interpolazione in Perl, dunque la parte $100
viene lasciata così com'è.
In alcune shell potete racchiudere il nome della variabile in parentesi graffe per eliminare ambiguità nel caso questo sia seguito da altri caratteri alfanumerici (o underscore). Siete anche obbligati a farlo quando interpolate una variabile all'interno di una stringa per separare il nome della variabile da una successiva coppia di due-punti o da un apostrofo, poiché queste verrebbero altrimenti trattate come separatori di package:
$chi = "Larry"; print PASSWD "${chi}::0:0:Superuser:/:/bin/perl\n"; print "Diciamo ${chi}uccio per vezzeggiare '${chi}'no?.\n";
Senza le parentesi, Perl andrebbe a cercare la variabile $chiuccio
,
o $chi::0
o ancora $chi'no
. Queste ultime due risulterebbero
essere le variabili $0
e $no
nel package chi
, che
presumibilmente non esiste.
Qualunque identificativo in tali parentesi graffe viene forzato
ad essere una stringa, così come qualsiasi identificativo semplice
all'interno di un indice di hash. Nessuno dei due ha bisogno
di virgolette. Nel nostro esempio di prima, $giorni['Feb']
può
essere riscritto come $giorni{Feb}
, e le virgolette sarebbero
sottintese. D'altra parte, qualsiasi cosa più complicata come
indice verrà interpretata come espressione. Questo significa ad
esempio che $versione{2.0}++
è equivalente a
$versione{2}++
, non a $versione{'2.0'}++
.
Nota: l'uso delle Stringhe di Versione (v-string) è scoraggiato. Non saranno disponibili dopo Perl 5.8, i vantaggi marginali dati dalle v-string erano facilmente messi in secondo piano da un intero potenziale di Sorprese e Confusione.
Un letterale della forma v1.20.300.4000
è interpretato come una
stringa composta da caratteri con gli ordinali specificati. Questa
forma, nota come v-string, fornisce un modo alternativo e maggiormente
leggibile di costruire stringhe, piuttosto che utilizzare qualche
forma di interpolazione meno leggibile "\x{1}\x{14}\x{12c}\x{fa0}"
.
Risulta utile per rappresentare stringhe Unicode, e per confrontare
``numeri di versione'' utilizzando gli operatori di comparazione per
le stringhe, ossia cmp
, gt
, lt
ecc. Se ci sono due o più
punti nel letterale la v
all'inizio può essere omessa.
print v9786; # stampa uno smiley codificato UTF-8 "\x{263a}" print v102.111.111; # stampa "foo" print 102.111.111; # uguale
Tali letterali sono accettati sia da require
che da use
per
effettuare il controllo delle versioni. La variabile speciale
^V
contiene anche la stringa di versione dell'interprete Perl
che sta eseguendo lo script; consultate $^V in the perlvar manpage. Osservate
anche che utilizzare v-string per indirizzi IPv4 non è portabile
a meno che non utilizziate anche le funzioni inet_aton()
e
inet_ntoa()
del package Socket.
Da notare che a partire da Perl 5.8.1 le v-string a valore
singolo (come v65
) non sono più considerate v-string prima
di un operatore =>
(che viene di solito utilizzato per
separare le chiavi di una hash dai valori), ma sono interpretate
come stringhe letterali ('v65'). Esse erano v-string da
Perl 5.6.0 a Perl 5.8.0, ma questo causava più confusione e
problemi che benefici. Le v-string multinumeriche come
v65.66
e 65.66.67
continuano ad essere sempre v-string.
I letterali __FILE__, __LINE__ e __PACKAGE__ sono speciali e
rappresentano nell'ordine il nome del file sorgente corrente, il
numero di riga ed il nome del package nel particolare punto
del programma in cui vengono utilizzati. Possono essere utilizzati
solo come token separati, non vengono interpolati all'interno
delle stringhe. Se non esiste un package corrente (a causa
della mancanza della direttiva package
), __PACKAGE__ ha valore
undef
.
I due caratteri di controllo ^D e ^Z, insieme ai token __END__ e __DATA__, possono essere utilizzati per indicicare la conclusione logica dello script, prima della fine del file in cui è contenuto. Qualunque dato successivo viene ignorato.
Il testo successivo a __DATA__ può essere letto utilizzando il
filehandle PACKNAME::DATA
, ove PACKNAME
è il package
corrente al momento in cui viene incontrato il token __DATA__ stesso.
Il filehandle viene tenuto aperto e punta ai dati che seguono __DATA__;
è responsabilità del programma chiudere questo filehandle quando ha
terminato le operazioni di lettura. Per compatibilità con script più
vecchi, scritti prima dell'introduzione di __DATA__, __END__ si comporta
come __DATA__ nello script di livello più elevato (ma non nei file
caricati con require
o do
), e mette a disposizione i contenuti
rimanenti attraverso il filehandle main::DATA
.
Consultate the SelfLoader manpage per maggiori ragguagli su __DATA__ ed un esempio di utilizzo. Osservate anche che non potete leggere dal filehandle DATA in blocco BEGIN, poiché questo viene eseguito non appena viene incontrato (durante la compilazione), in un punto in cui il corrispondente token __DATA__ (o __END__) non è stato ancora incontrato.
Una parola che non ha altra interpretazione nella grammatica Perl viene
considerata come se fosse una stringa con virgolette, e viene detta
``bareword'' [parola nuda, N.d.T.]. Come per filehandle ed etichette,
una bareword formata unicamente da lettere minuscole rischia di
entrare in conflitto con possibili parole riservate del linguaggio
che verranno introdotte in futuro; se utilizzate la direttiva
use warnings
o l'opzione -w, inoltre, Perl stamperà un avviso
per ciascuna parola di questo tipo. Alcune persone vorrebbero bandire
del tutto le bareword. Se dite
use strict 'subs';
allora qualsiasi bareword tale da NON venire interpretata come una
chiamata a funzione produce un errore di compilazione. Tale restrizione
continua fino alla fine del blocco contenente l'uso della direttiva suddetta;
in più, un blocco più interno può disabilitare tale comando utilizzando
no strict 'subs'
.
Gli array e le slice sono interpolate, all'interno di stringhe racchiuse
da virgolette doppie, unendo gli elementi con il delimitatore specificato
nella variabile $"
(se state utilizzando use English
può essere
specificato anche come $LIST_SEPARATOR
), che risulta essere costituito
da un singolo spazio per default. I seguenti frammenti sono equivalenti:
$temp = join($", @ARGV); system "echo $temp";
system "echo @ARGV";
All'interno dei pattern di ricerca (che seguono le stesse regole di
sostituzione proprie delle virgolette doppie) c'è spazio per una
sfortunata ambiguità: /$pippo[pluto]/
va interpretata come
/${pippo}[pluto]/
(ove [pluto]
è una classe di caratteri per l'espressione
regolare) o come ${pippo[pluto]}
(ove [pluto]
è un indice nell'array
@pippo
)? Se @pippo
non esiste, allora indubbiamente ci troviamo di
fronte ad una classe di caratteri. Se @pippo
esiste, d'altra parte,
Perl cerca di tirare ad indovinare su come considerare [pluto]
, e nella
maggior parte delle volte è corretto. Se però sbaglia, o siete giusto un
pizzico paranoici, potete forzare l'interpretazione da voi ritenuta
corretta utilizzando le parentesi graffe, come fatto in precedenza.
Se state cercando informazioni su come utilizzare here-document, che si trovavano a questo punto di questa pagina del manuale, sappiate che sono state spostate in Quote and Quote-like Operators in the perlop manpage [Virgolette ed Operatori Similari, N.d.T.].
I valori di una lista sono denotati separando i singoli valori utilizzando delle virgole (e racchiudendo la lista fra parentesi, laddove le regole di precedenza lo richiedano):
(LISTA)
In un contesto in cui non viene richiesta una lista di valori, il valore che risulta dalla lista è semplicemente quello dell'elemento finale, proprio come con l'operatore virgola nel linguaggio C. Ad esempio:
@pippo = ('cc', '-E', $pluto);
assegna l'intera lista all'array c<@pippo>, ma d'altra parte:
$pippo = ('cc', '-E', $pluto);
assenga alla variabile scalare $pippo
il valore della variabile $pluto
.
Osservate che il valore di un array reale, valutato in contesto
scalare, si traduce nella lunghezza dell'array; il seguente frammento
assegna dunque il valore 3 alla variabile $pippo
:
@pippo = ('cc', '-E', $pluto); $pippo = @pippo; # $pippo viene posta a 3
Potete opzionalmente inserire una virgola prima della parentesi di chiusura di una lista di letterali, ossia potete dire:
@pippo = ( 1, 2, 3, );
Per utilizzare un here-document per assegnare valori agli elementi di un array, una riga per elemento, potreste utilizzare l'approccio che segue.
@salse = <<Fine_Righe =~ m/(\S.*\S)/g; pomodoro normale pomodoro condito chili verde pesto vino bianco Fine_Righe
Le LISTE effettuano automaticamente l'interpolazione sulle sottoliste. In poche parole, quando la LISTA viene valutata, ciascun elemento componente viene valutato in contesto lista, e la lista totale che ne consegue viene intepolata all'interno di LISTA come se quegli elementi individuali fossero membri di LISTA. Per questo motivo, gli array e le hash perdono la propria identità all'interno di una LIST; la semplice lista:
(@pippo, @pluto, &UnaFunzioneQualunque, %boh)
contiene tutti gli elementi di @pippo
, seguiti da tutti gli
elementi di @pluto
, seguiti da tutti gli elementi restituiti dalla
funzione chiamata UnaFunzioneQualunque, seguiti infine dalle coppie chiave/valore
dell'hash %boh
. Per generare un riferimento ad una lista che
NON interpola consultate the perlref manpage.
La lista vuota viene rappresentata da (). Interpolarla in una lista non ha effetti. Perciò, ((),(),()) è equivalente a (). In modo simile, interpolare un array senza elementi è identico a pensare che nessun array sia stato mai interpolato fino a questo punto.
L'interpolazione va a braccetto con il fatto che le parentesi di
apertura e chiusura sono opzionali (eccezion fatta per quando
tali parentesi sono necessarie per le regole di precedenza) e che le
liste possono essere provviste di una virgola opzionale a
denotare che la presenza di virgole ripetute nella lista costituiscono
una sintassi legale. La lista 1,,3
risulta dalla concatenazione
di due liste, 1,
e 3
, la prima delle quali termina con la
virgola opzionale descritta. 1,,3
è in realtà (1,),(3)
che a sua
volta corrisponde a 1,3
(e similmente si ha che 1,,,3
è
equivalente a C(1,),(,),3>, che è 1,3
, e così via. Ovviamente non
vi stiamo suggerendo di offuscare il codice utilizzando questa
caratteristica.
Un valore di tipo lista può anche essere indicizzato come un array normale; dovete però inserire la lista fra parentesi per evitare ambiguità. Ad esempio:
# La funzione `stat' restituisce un valore lista $tempo = (stat($file))[8];
# ERRORE DI SINTASSI NELLA RIGA CHE SEGUE $tempo = stat($file)[8]; # OOPS, HO DIMENTICATO LE PARENTESI
# Trova una cifra esadecimale $cifra_esadecimale = ('a','b','c','d','e','f')[$cifra-10];
# Un "operatore virgola" al contrario return (pop(@pippo),pop(@pippo))[0];
Si può effettuare un'assegnazione ad una lista solo quando ciascun elemento della lista è esso stesso un possibile valore legale per il lato sinistro di una assegnazione:
($a, $b, $c) = (1, 2, 3);
($map{'rosso'}, $map{'blu'}, $map{'verde'}) = (0x00f, 0x0f0, 0xf00);
Un'eccezione a questa regola consiste nel fatto che potete assegnare
undef
ad una lista. Questo approccio è utile quando si vogliono
ignorare alcuni risultati di una funzione.
($dev, $ino, undef, undef, $uid, $gid) = stat($file);
L'assegnazione di una lista in contesto scalare restituisce il numero di elementi prodotti dall'espressione regolare posta alla destra dell'operatore di assegnazione.
$x = (($pippo,$pluto) = (3,2,1)); # imposta $x a 3, non a 2 $x = (($pippo,$pluto) = f()); # imposta $x al conteggio di quanto # restituito da f()
Ciò è comodo quando volete effettuare un'assegnazione di lista in contesto Booleano, poiché molte funzioni restituiscono la lista nulla in uscita, che una volta assegnata produce 0, il quale a sua volta viene interpretato come falso.
Questa proprietà è anche alla base di un utile idioma per eseguire una funzione o per effettuare un'operazione in contesto lista, per poi contare il numero di valori restituiti, assegnando il risultato ad una lista vuota e poi utilizzando l'assegnazione in contesto scalare. Ad esempio, il codice che segue:
$conteggio = () = $testo =~ /\d+/g;
inserisce dentro $conteggio
il numero di gruppi di cifre numeriche trovate
in $testo
. Questo accade grazie al fatto che il pattern match
avviene in contesto lista (dal momento che viene assegnato ad una
lista vuota), ragion per cui verrà restituita una lista di tutte le parti
del testo che verificano l'espressione regolare. La successiva assegnazione
in contesto scalare tradurrà tale lista nel numero degli elementi che
la compongono (in questo caso, il numero di volte che l'espressione
regolare è stata verificata) ed imposterà $conteggio
. Osservate che
usando semplicemente:
$conteggio = $testo =~ /\d+/g;
non funzionerebbe, perché un pattern match in contesto scalare restituisce solo un valore vero o falso, invece che il numero di confronti positivi.
L'ultimo elemento di un'assegnazione di lista può essere un array o una hash:
($a, $b, @resto) = split; my($a, $b, %resto) = @_;
In realtà, potete mettere un array o una hash ovunque nella lista, ma
il primo che viene incontrato farà razzia di tutti i valori, e qualunque
altro elemento successivo assumerà valore undef
. Potrebbe anche esservi
utile in un my()
o un local()
.
Una hash può essere inizializzata utilizzando una lista letterale contenente coppie di elementi che verranno interpretate come chiave e valore:
# stessa assegnazione di map riportata in precedenza %map = ('rosso',0x00f,'blu',0x0f0,'verde',0xf00);
Mentre potete normalmente scambiare liste letterali e array, ciò non è possibile nel caso delle hash. Solo perché potete indicizzare un valore in una lista come un normale array non vuol dire che possiate indicizzarlo come una hash. In maniera del tutto analoga, le hash incluse all'interno di liste (ivi incluse le liste di parametri e quelle restituite dalle funzioni) sono sempre appiattite in coppie chiave/valore. Questo è un buon motivo per utilizzare i riferimenti, a volte.
Spesso risulta più leggibile utilizzare l'operatore =>
fra le
coppie chiave/valore. Questo operatore è sostanzialmente solo un
sinonimo visivamente più efficace per l'operatore ``virgola'', ma ha
anche l'effetto di modificare l'operando alla sua sinistra per essere
interpretato come una stringa se è una bareword che risulterebbe essere
un semplice identificatore ammissibile (=>
non mette virgolette
sugli identificatori compositi che contengono doppi due-punti). Questo
rende possibile inizializzare le hash in maniera simpatica:
%map = ( rosso => 0x00f, blu => 0x0f0, verde => 0xf00, );
o per iniziare riferimenti ad hash da utilizzare come record:
$rec = { strega => 'Mabella la Senza Pieta`', gatto => 'Fuffi il feroce', data => '10/31/1776', };
o per impostare parametri con nome per chiamare funzioni complicate:
$campo = $query->radio_group( name => 'nome_gruppo', values => ['eenie','meenie','minie'], default => 'meenie', linebreak => 'true', labels => \%labels );
[Vari elementi sono nome, valori, valore_di_default, a_capo ed etichette. Si è preferito lasciare i nomi originali visto il chiaro riferimento al modulo CGI di Lincoln D. Stein. N.d.T.]
Osservate che il fatto che la hash sia inizializzata in questo ordine non significa che gli elementi verranno fuori nello stesso ordine. Consultate sort in the perlfunc manpage per avere esempi su come ottenere un'uscita ordinata.
Un array viene indicizzato specificando un segno di dollaro ($
),
seguito dal nome dell'array (senza la @
iniziale), seguito dall'indice
posto all'interno di parentesi quadre. Ad esempio:
@mioarray = (5, 50, 500, 5000); print "L'elemento numero 2 contiene ", $mioarray[2], "\n";
Gli indici di un array iniziano da 0. Un indice negativo va a prendere
il valore corrispondente iniziando dalla fine. Nel nostro esempio,
$mioarray[-1]
corrisponde al valore 5000, e $mioarray[-2]
a 500.
Le indicizzazioni di una hash sono simili, solo che invece di parentesi quadre occorre utilizzare parentesi graffe. Ad esempio:
%scienziati = ( "Newton" => "Isaac", "Einstein" => "Albert", "Darwin" => "Charles", "Feynman" => "Richard", );
print "Il nome di Darwin e' ", $scienziati{"Darwin"}, "\n";
Il metodo più comune di accedere ad un array o ad una hash è un elemento alla volta. Potete indicizzare anche una lista per prendere un singolo elemento.
$chisono = $ENV{"USER"}; # un elemento dalla hash $antenato = $ISA[0]; # un elemento dall'array $dir = (getpwnam("daemon"))[7]; # analogo, ma con la lista
Una slice accede a parecchi elementi di una lista, di un array o di una hash contemporaneamente, utilizzando una lista di indici; risulta più conveniente che non scrivere gli elementi singoli come lista di valori scalari separati.
($lui, $lei) = @gente[0, -1]; # slice di array @loro = @gente[0 .. 3]; # slice di array ($chi, $home) = @ENV{"USER", "HOME"}; # slice di hash ($uid, $dir) = (getpwnam("daemon"))[2, 7] # slice di lista
Poiché potete effettuare assegnazioni a liste di variabili, potete anche effettuarle ad una slice di array o hash:
@giorni[3 .. 5] = qw/ Mer Gio Ven /; @colori{'rosso', 'blu', 'verde'} = (0xff0000, 0x0000ff, 0x00ff00); @gente[0, -1] = @gente[-1, 0];
Queste assegnazioni corrispondono esattamente a
($giorni[3], $giorni[4], $giorni[5]) = qw/ Mer Gio Ven /; ($colori{'rosso'}, $colori{'blu'}, $colori{'verde'}) = (0xff0000, 0x0000ff, 0x00ff00); ($gente[0], $gente[-1]) = ($gente[-1], $gente[0]);
Poiché cambiare una slice cambia l'array o la hash originale dalla quale
proviene, un costrutto foreach
modificherà alcuni, o anche tutti, i
valori dell'array o della hash.
foreach (@array[ 4 .. 10 ]) { s/pietro/paolo/ }
foreach (@hash{qw[ chiave1 chiave2 ]}) { s/^\s+//; # elimina gli spazi iniziali s/\s+$//; # elimina gli spazi finali s/(\w+)/\u\L$1/g; # maiuscole ad inizio di ogni parola }
Una slice di una lista vuota è ancora una lista vuota. Perciò:
@a = ()[1,0]; # @a non ha elementi @b = (@a)[0,1]; # @b non ha elementi @c = (0,1)[2,3]; # @c non ha elementi
Ma:
@a = (1)[1,0]; # @a ha due elementi @b = (1,undef)[1,0,2]; # @b ha tre elementi
Ciò rende semplice scrivere cicli che si interrompono quando viene restituita una lista nulla:
while ( ($home, $utente) = (getpwent)[7,0]) { printf "%-8s %s\n", $utente, $home; }
Come abbiamo osservato in precedenza, l'assegnazione di una lista in contesto scalare restituisce il numero di elementi di quanto si trova alla destra dell'assegnazione. La lista vuota non ha elementi, per cui quando il file delle password è terminato il risultato è 0 invece che 2.
Se siete un po' confusi sul perché dovete utilizzare una @
in una
slice di hash invece che %
, provate a pensarla così: il tipo di
parentesi (quadre o graffe) indica se si sta guardando in un array o
in una hash. D'altra parte, il carattere iniziale ($
o @
) prima
del nome dell'array o della hash indica se volete ottenere un valore
singolare (ossia, uno scalare) o plurale (una lista).
Perl utilizza un tipo interno detto typeglob per contenere un intero
elemento della tabella dei simboli. Il prefisso di una typeglob è un
carattere *
, perché rappresenta tutti i tipi. Questo era il sistema
preferito per passare array ed hash per riferimento in una funzione, ma
ora abbiamo riferimenti veri e propri, per cui se ne ha bisogno di rado.
L'utilizzo principale delle typeglob nel Perl moderno si ha nella creazione di alias nella tabella dei simboli. Questa assegnazione:
*questo = *quello;
rende $questo
un alias per $quello
, @questo
un alias per @quello
,
%questo
un alias per %quello
, &questo
un alias per &quello
e
così via. È molto più sicuro utilizzare un riferimento. Questa assegnazione:
local *Qui::blu = \$Altrove::verde;
rende $Qui::blu
un alias temporaneo per $Altrove::verde
, ma non
rende @Qui::blu
un alias temporaneo per @Altrove::verde
, o
%Qui::blu
un alias temporaneo per %Altrove::verde
ecc. Consultate
Symbol Tables in the perlmod manpage [Tabelle dei Simboli, N.d.T.]
per altri esempi. Per quanto possa sembrare
strano, questo meccanismo è alla base di tutto il sistema di import/esport
dei moduli.
Un altro utilizzo per i typeglob è per passare filehandle all'interno di funzioni o per creare nuovi filehandle. Se avete bisogno di un typeglob per salvare un filehandle, fatelo così:
$fh = *STDOUT;
o forse meglio con un riferimento reale, come:
$fh = \*STDOUT;
Consultate the perlsub manpage per altri esempi di utilizzo di questi riferimenti come filehandle indiretti all'interno delle funzioni.
I typeglob sono anche un modo per creare un filehandle locale utilizzando
l'operatore local()
. Questi durano finché il loro blocco non si
chiude, ma possono essere restituiti. Ad esempio:
sub nuova_open { my $percorso = shift; local *FH; # non my ma local! open (FH, $percorso) or return undef; return *FH; } $fh = nuova_open('/etc/passwd');
Ora che abbiamo la notazione *pippo{COSA}
, i typeglob non sono più
tanto utilizzati per la manipolazione di filehandle, sebbene siano ancora
necessari per passare handle di file o di directory nuovi di zecca dentro
o fuori dalle funzioni. Ciò dipende dal fatto che
*HANDLE{IO}
funziona solo se HANDLE è stato già utilizzato
come handle. In altre parole, *FH
deve essere utilizzato per creare un nuovo elemento nella tabella dei
simboli; *pippo{COSA}
non sa farlo. Quando siete in dubbio, utilizzate
*FH
.
Tutte le funzioni che sono in grado di creare filehandle (open()
,
opendir()
, pipe()
, socketpair()
, sysopen()
, socket()
e
accept()
) creano automaticamente un filehandle anonimo se
l'handle passato loro è una variabile scalare non inizializzata. Ciò
consente di utilizzare costrutti come open(my $fh, ...)
e
open(local $fh, ...)
per creare filehandle che verranno comodamente
chiusi in automatico quando lo scope termina, ammesso che non rimangano
altri riferimenti. Ciò elimina in larga parte la necessità di utilizzare
typeglob in fase di apertura di filehandle che devono essere passati
``in giro'', come nell'esempio che segue:
sub mia_open { open my $fh, "@_" or die "fallita chiamata a open() '@_': $!"; return $fh; }
{ my $f = mia_open("</etc/motd"); print <$f>; # $f viene chiusa implicitamente a questo punto }
Osservate che, se viene usata una variabile scalare inizializzata, il
risultato è differente: my $fh = 'zzz'; open($fh, ...)
è
equivalente a open( *{'zzz'}, ...)
. use strict 'refs'
proibisce
questa pratica.
Un altro modo per creare un filehandle anonimo si ha utilizzando
il modulo Symbol o con il modulo IO::Handle e la sua genia. Questi
moduli hanno il vantaggio di non nascondere tipi differenti con lo stesso
nome quando si usa local()
. Per un esempio, si veda in fondo a
open() in the perlfunc manpage.
Consultate the perlvar manpage per una descrizione delle variabili predefinite
in Perl e per una discussione sui nomi ammissibili per le variabili.
Vedete the perlref manpage, the perlsub manpage e Symbol Tables in the perlmod manpage
[Tabelle dei Simboli, N.d.T.] per maggiori
ragguagli sui typeglob e la sintassi *pippo{COSA}
.
La versione su cui si basa questa traduzione è ottenibile con:
perl -MPOD2::IT -e print_pod perldata
Per maggiori informazioni sul progetto di traduzione in italiano si veda http://pod2it.sourceforge.net/ .
Traduzione a cura di Flavio Poletti.
Revisione a cura di dree.
NOME |