NOME
perldata - Tipi di dato in Perl
DESCRIZIONE
Nomi di variabile
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 perlref). 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 perlmod 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 perlref.
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 perlop e perlre). 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 perlvar.
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 fare è ridondante in italiano. 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 perlref.
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).
Contesto
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 perlfunc per sapere come fare a stabilire dinamicamente in quale contesto è stata chiamata la vostra funzione.
Valori scalari
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 perlref. 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 perlre):
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
Costruttori di valori scalari
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
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 perlop 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 perlfunc e "oct" in perlfunc 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.
Stringhe di Versione
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 perlvar. 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.
Letterali Speciali
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 SelfLoader 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.
Bareword
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'
.
Delimitatore di Unione di Array
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 perlop [Virgolette ed Operatori Similari, N.d.T.].
Costruttori di Valori di Lista
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<Egrave>, $pluto);
assegna l'intera lista all'array c<@pippo>, ma d'altra parte:
$pippo = ('cc', '-E<Egrave>, $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<Egrave>, $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 perlref.
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 perlfunc per avere esempi su come ottenere un'uscita ordinata.
Indicizzazione
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";
Slice
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).
Typeglob e Filehandle
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 perlmod [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 perlsub 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 perlfunc.
VEDETE ANCHE
Consultate perlvar per una descrizione delle variabili predefinite in Perl e per una discussione sui nomi ammissibili per le variabili. Vedete perlref, perlsub e "Symbol Tables" in perlmod [Tabelle dei Simboli, N.d.T.] per maggiori ragguagli sui typeglob e la sintassi *pippo{COSA}
.
TRADUZIONE
Versione
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/ .
Traduttore
Traduzione a cura di Flavio Poletti.
Revisore
Revisione a cura di dree.
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 944:
Non-ASCII character seen before =encoding in 'è'. Assuming CP1252