Michele Beltrame
b. I tipi di dato e gli operatori
http://www.perl.it/documenti/articoli/2007/12/i-tipi-di-dato.html
© Perl Mongers Italia. Tutti i diritti riservati.

Data di pubblicazione: Questo articolo è stato pubblicato su Dev n°76 e in questo sito per autorizzazione espressa del "Gruppo Editoriale Infomedia" (http://www.infomedia.it).

© 2007 Michele Beltrame.

1. Introduzione 

2. Scalari 

3. Operazioni semplici con i numeri 

4. Operazioni semplici con le stringhe 

5. Il costrutto if, gli operatori logici ed i confronti tra stringhe e numeri 

6. Stringa o numero? Una questione di contesto 

7. Conclusioni 

Introduzione

La prima cosa che si apprende quando si studia un linguaggio di programmazione è, naturalmente dopo il classico programma che scrive Ciao, Mondo!, la gestione dei dati: ciò significa capire quali tipi di dato il linguaggio mette a disposizione, e quali operatori si devono utilizzare per gestire tali dati. In Perl la vita è abbastanza facile, in quanto ad esempio non servirebbe dichiarare le variabili. Il condizionale è d'obbligo, poiché è raccomandabile forzare il linguaggio a richiederne la dichiarazione: questo toglie un po' di libertà al programmatore, ma permette di creare programmi più ordinati e rende il debugging molto più rapido. La dichiarazione delle variabili verrà comunque introdotta nelle lezioni successive.

 Scalari

Il glossario della prima edizione di Programming Perl indica uno scalare come "un valore semplice, come un numero o una stringa. Oppure, qualcuno che scala le montagne". Nell'edizione successiva del testo, l'unica che è ora possibile trovare nelle librerie, questo umorismo è purtroppo sparito dal glossario, e ne è rimasta solo la parte "seria". In ogni caso, come da definizione, uno scalare è il tipo di dato fondamentale: stringhe di qualunque tipo e numeri, sia interi che decimali, sono valori scalari. Assegnare un valore numerico ad uno scalare è piuttosto semplice:

$numero = 1974;

Il dollaro è il carattere che identifica uno scalare, e va sempre posto prima del nome della variabile. L'operatore di assegnazione è il segno di uguale (=). Per vedere il contenuto della variabile creata basta scrivere:

print "$numero\n";

Un numero può essere assegnato utilizzando varie notazioni: ad esempio è disponibile $mynum= 287.32 per i decimali, $mynum = 7.5E15 per gli esponenziali, $mynum = 0xffff per gli esadecimali oppure $mynum = 0377 per gli ottali. Per quanto riguarda le stringhe, il discorso è notevolmente più articolato. Una stringa può essere inzializzata nel seguente modo:

$stringa = 'Ciao, Mondo\n';

oppure così:

$stringa = "Ciao, Mondo\n";

La differenza tra l'uso dei singoli apici e quello dei doppi apici è immediatamente comprensibile se si stampa a video la stinga creata: quella inizializzata utilizzando i singoli apici apparirà come Ciao, Mondo\n, mentre la seconda sarà visualizzata come Ciao, Mondo seguita da un newline (passaggio alla linea successiva). La differenza è quindi nell'interpolazione: per le stringhe inizializzate con i doppi apici Perl interpreta e sostituisce i caratteri a seguito di un backslash (\), mentre per quelle inizializzate con i singoli apici ciò non avviene (eccezion fatta per \\ e \', indispensabili per inserire il backslash e l'apice nella stringa). Se si inizializza una variabile utilizzando i doppi apici, anche i nomi di altre variabili inseriti all'interno di essa vengono interpolati, quindi ad esempio:

$stringa1 = "Ciao,";
$stringa2 = "$stringa1 Mondo!";

produrrà una variabile $stringa2 contenente il classico testo Ciao, Mondo!. Va notato che quanto detto vale anche per le funzioni che accettano stringhe come parametri, quali print: esse accettano sia singoli che doppi apici, e le stesse regole sono applicate. Oltre a \n, molti altri caratteri possono essere utilizzati a seguito di un backslash per rappresentare stringhe speciali: una lista di essi è visibile in tabella 1.

CarattereSignificato
\n
Newline
\r
Carriage return (sotto Windows le righe finiscono con \r\n, sotto Unix solo con \n)
\t
Tabulazione orizzontale
\f
Form feed
\b
Backspace
\a
Allarme (causa l'emissione di un suono dallo speaker del computer)
\e
Carattere ESCAPE
\033
Qualsiasi carattere, in notazione ottale (in questo caso è ESCAPE)
\x7f
Qualsiasi carattere, in notazione esadecimale (in questo caso è ESCAPE)
\cS
Qualsiasi carattere di controllo (in questo caso CRTL-S)
\\
Backslash
\"
Apici doppi
\u
Fa sì che il carattere successivo a \u sia convertito in maiuscolo
\l
Fa sì che il carattere successivo a l\ sia convertito in minuscolo
\U
Fa sì che tutti i caratteri successivi a \U siano convertiti in maiuscolo
\L
Fa sì che tutti i caratteri successivi a \L siano convertiti in maiuscolo
\Q
Fa sì che tutti i caratteri successivi e non alfanumerici siano automaticamente preceduti da backslash
\E
Termina l'effetto di \U, \L oppure \Q

 Operazioni semplici con i numeri

Gli operatori disponibili per le operazioni con gli scalari a valore numerico sono quelli classici. Ad esempio:

$c = $a + $b;

memorizzerà in $c la somma dei valori di $a e $b. Altre possibilità sono la sottrazione (operatore -), la moltiplicazione (operatore *), la divisione (operatore /), il resto della divisione (modulo, operatore %) e l'esponenziale (operatore **). È possibile utilizzare una forma abbreviata per sommare un numero fisso ad una variabile. Ad esempio, al posto $a = $a * 2, si può scrivere:

$a *= 2;

Quando si desidera sottrarre o aggiungere una sola unità ad una variabile a contenuto numerico esiste, come in C, una forma ancora più abbreviata, e cioè la semplice istruzione $a++ oppure ++$a per quanto riguarda l'incremento, e $a-- oppure --$a per quanto riguarda il decremento. Cosa cambia tra anteporre e postporre l'operatore? Entrambi hanno lo stesso effetto (e cioè di incrementare o decrementare una variabile), ma analizzando il contesto si nota una differenza fondamentale. Vediamo un esempio:

$a = 1;
$b = 1;
print $a++, "\n";
print ++$b, "\n";

L'output è rappresentato da due righe, una con scritto 1 e l'altra con scritto 2, benché alla fine tutte e due le variabili assumano valore 2. La differenza tra la prima e la seconda sintassi risiede quindi nel momento in cui avviene l'incremento: se l'operatore è posto dopo il nome della variabile, essa viene prima utilizzata nel contesto (la funzione print in questo caso) e poi incrementata; se l'operatore è invece anteposto al nome della variabile, essa viene prima incrementata e poi utilizzata nel contesto.

 Operazioni semplici con le stringhe

Come per i numeri, anche per le stringhe il Perl fornisce una serie di operatori utili alla loro gestione. Per concatenare due stringhe si procede come da seguente esempio:

$a = "prova!";
$b = "questa è una " . $a;

L'operatore da usare è quindi il punto. In realtà, utilizzando i doppi apici, l'operatore di concatenazione è del tutto superfluo, in quanto sarebbe sufficiente la seguente forma:

$b = "questa è una $a";

Con questo non si vuole assolutamente dire che tale operatore è del tutto superfluo: esso è infatti utile quando ad esempio si vuole inserire in una stringa il valore restituito da una funzione, come vedremo nelle successive lezioni. L'operatore risulta inoltre utile se una variabile va inserita all'interno di un testo senza essere separata da spazi. Ad esempio potremmo scrivere quanto segue:

$a = "pr";
$b = "questa è una ".$a."ova";

In $b avremo il solito testo questa è una prova. Non avrebbe invece funzionato se come seconda riga avessimo usato:

$b = "questa è una $aova";

in quanto il nome di variabile preso in considerazione sarebbe stato $aova e non $a. In tipico stile Perl c'è naturalmente un altro metodo per ottenere lo stesso scopo. Esso prevede l'uso delle parentesi graffe:

$b = "questa è una ${a}ova";

Sorprendentemente, le stringhe si possono anche moltiplicare:

$a = "abc";
$b = "abc" x 3;

Il risultato è la stringa $a ripetuta tre volte, e cioè abcabcabc. Un importantissimo operatore per le stringhe è poi =~, cioè quello relativo al pattern matching: ad esso ed alle famose regular expression verrà dedicata un'intera lezione.

 Il costrutto if, gli operatori logici ed i confronti tra stringhe e numeri

Comprendere il funzionamento della programmazione condizionale è indispensabile: al verificarsi di una determinata condizione viene eseguito un certo codice, al verificarsi di un'altra altro codice, e via dicendo. Il costrutto principe della programmazione condizionale è if-elsif-else, di cui vediamo subito un esempio:

if ($a == 1) { print "vale 1!"; }
elsif ($a >= 2) { print "vale 2 o più!"; }
else { print "vale altro!"; }

Il codice posto tra parentesi graffe viene eseguito solo se l'espressione immediatamente precedente restituisce un valore vero (in questo caso se la comparazione è esatta); se il valore booleano restituito è falso nulla viene invece eseguito. In questo esempio confrontato il valore della variabile $a: se è uguale a 1 viene stampato a video il testo vale 1!, se invece è maggiore o uguale a 2 viene stampato vale 2 o più!, mentre in tutti gli altri casi viene stampato vale altro! L'istruzione elsif, a differenza di if, viene eseguita solo se l'if precedente ha avuto esito negativo; else a sua volta viene eseguita solo in caso di esito negativo dei confronti avvenuti in precedenza. Non è assolutamente indispensabile che ad un if faccia seguito un elsif oppure un else, ma questi ultimi due richiedono assolutamente la presenza del primo.

Tutti gli operatori disponibili per il confronto dei numeri e delle stringhe sono visibili in tabella 2.

ComparazioneOperatore numericoOperatore stringaValore restituito
Uguaglianza
==
eq
Vero se $a è uguale a $b, falso altrimenti
Disuguaglianza
!=
ne
Vero se $a è diverso da $b, falso altrimenti
Minoranza stretta
<
lt
Vero se $a è minore di $b
Maggioranza stretta
>
gt
Vero se $a è maggiore di $b
Minoranza
<=
le
Vero se $a è minore o uguale a $b
Maggioranza
>=
ge
Vero se $a è maggiore o uguale a $b
Comparazione
<=>
cmp
-1 se $b è maggiore, 0 se $a è uguale a $b, 1 se $a è maggiore

Con una sola istruzione if oppure elsif si possono eseguire più comparazioni, utilizzando gli operatori logici per collegarle l'una all'altra: essi sono fondamentalmente tre: ||, && e !. Di questi esistono anche gli equivalenti a priorità più bassa, che sono rispettivamente or, and e not. La questione della priorità tra gli operatori in Perl è abbastanza delicata, e verrà approfondita in futuro: per ora il consiglio è quello di includere le varie espressioni tra parentesi quando si è nel dubbio. Tornando alla funzione dei vari operatori, analizziamo i seguenti esempi:

if ( ($a == 1) && ($b == 2) ) { print "OK!"; }
if ( ($a == 1) || ($b == 2) ) { print "OK!"; }
if ( !($a == 1) ) { print "OK!"; }

Nel primo caso il codice condizionale verrà eseguito solo se si verificano entrambe le condizioni: $a deve valere 1 e $b deve valere 2. Nel secondo caso per garantire l'esecuzione del codice condizionale è sufficiente che una delle due condizioni si verifichi, oppure entrambe: solo il non verificarsi di alcuna delle due provocherà la mancata esecuzione di print. La terza riga provoca invece l'esecuzione della parte condizionale solo se la condizione è falsa: il ! (not) ribalta infatti il risultato dell'espressione logica, quindi $a deve essere di fatto diverso da 1. Si poteva anche scrivere:

if ($a != 1) { print "OK!"; }

Il Perl mostra tuttavia la sua eleganza mettendo anche a disposizione un costrutto che, pur avendo un funzionamento del tutto analogo a if, ribalta automaticamente il significato logico dell'espressione. La riga precedente può quindi essere scritta anche così:

unless ($a == 1) { print "OK!"; }

 Stringa o numero? Una questione di contesto

In Perl il problema della conversione di una stringa in numero e viceversa è risolto dall'interprete: esso converte automaticamente gli scalari tra un tipo e l'altro a seconda del contesto in cui essi sono inseriti. Poniamo di definire due variabili come segue:

$a = "100";
$b = 200;

Il primo scalare è definito come stringa, il secondo come intero. Possiamo tuttavia tranquillamente effettuare una somma:

$c = $a + $b;

ed ottenere correttamente 300 come risultato, grazie alla conversione automatica della stringa in valore numerico. Allo stesso modo funzionerà:

$c = $a . $b;

Il risultato in questo caso è la stringa 100200, grazie alla conversione automatica in stringa del numero contenuto in $b, effettuata a causa della presenza dell'operatore di concatenazione. È importante notare che queste conversioni vengono effettuate automaticamente anche quando si effettuano dei confronti, come ad esempio avviene all'interno di un'istruzione if. Anche in questo caso è l'operatore usato a decidere il contesto: se ad esempio si usa == verrà testata l'uguaglianza tra due numeri, se si usa eq verrà invece testata l'uguaglianza tra due stringhe.

 Conclusioni

Abbiamo visto ed analizzato i tipi base di dato in Perl. Come si nota, non è mai necessario indicare il tipo di variabile, come ad esempio va fatto in C: è l'interprete a gestire il tutto, e ad occuparsi delle conversioni qualora necessario. Nella prossima puntata esamineremo le due strutture dati fondamentali messe a disposizione dal Perl: gli array e gli hash.

  1. Ellen Siever, Stephen Spainhour, Nathan Patwardhan - "Perl in a Nutshell", O'Reilly & Associates, Gennaio 1999
  2. Larry Wall, Randal L. Schwartz - "Programming Perl", O'Reilly & Associates, Gennaio 1991
  3. Larry Wall, Tom Christiansen, Randal L. Schwartz - "Programming Perl (2nd edition)", O'Reilly & Associates, Settembre 1996