Perl/Funzioni

Wikibooks, manuali e libri di testo liberi.
Indice del libro


Le funzioni sono dei raggruppamenti di istruzioni "tipo i blocchi" ma con delle caratteristiche in più. Queste sono:

  1. un nome (assimilabile ad un'etichetta)
  2. eventuali parametri
  3. eventuali valori di ritorno

per indicare una funzione il Perl adotta la parola chiave sub (in inglese subrutine).


sub <nome> 
{
    ... istruzioni ...
}

esempio :

 sub miafunzione
 {
     print "ciao mondo\n";
 }
  
 miafunzione;

nell'esempio indicato la funzione "miafunzione" non usa parametri e non esplicita un valore di ritorno.

I parametri passati ad una funzione sono variabili. Occorre però prestare particolare attenzione al fenomeno della linearizzazione nel caso di array e hash.

Il vettore particolare @_[modifica]

Quando una funzione è invocata, eventuali parametri sono messi nel vettore particolare @_. Questa funzionalità è automatica pertanto ci si ritroverà queste informazioni in questo vettore.

Nel caso precedente che si è invocato miafunzione senza parametri pertanto @_ è vuoto.

L'interprete Perl applica a questo vettore speciale qualsiasi funzione che vuole o no dei parametri. quindi se si vedono nel codice comandi tipo

 @a = shift ;

in realtà è come se il codice scritto fosse:

 @a = shift @_;

I parametri[modifica]

I parametri di una funzione sono delle informazioni necessarie ad una funzione per svolgere il proprio compito. Vengono messi dopo la chiamata della funzione e sono separati da una virgola. La dichiarazione rimane inalterata ma la chiamata invece si modifica:

sub <nome>
{
    ... istruzioni ...
}
<nome> <parametro1>,<parametro2>,...,<parametroX>;

vediamo questo esempio:

 sub miafunzione
 {
     print "ciao mondo\n";
     my $a;
     my $c = 1;
     foreach $a (@_)
     {
         print "questo e' il parametro $c : $a\n";  
         $c++;
     }
 }

 miafunzione "pippo" , "pluto";

che produrrà:

ciao mondo
questo e' il parametro 1 : pippo
questo e' il parametro 2 : pluto

Come si può notare nella funzione NON si è specificato alcun argomento.Tutti questi sono stati messi in un array "speciale" chiamato @_. In questo array è possibile riottenere tutti i parametri passati.

Problema : se passo due array/hash ad una funzione come faccio a "tenerli" separati? (Vi ricordate del problema della linearizzazione?)

Soluzione: occorre usare i reference.Infatti non è possibile in un altro modo di evitare i problemi di linearizzazione.

Problema : se devo passare 2 scalari ed in array/hash come faccio ?

Soluzione: il parametro array/hash si mette per ultimo e gli scalari per primi : in questo modo dopo aver preso gli scalari (per esempio usando shift) si otterrà che i dati contenuti in @_ sono i dati contenuti nell'array/hash.

Il ritorno[modifica]

Ogni funzione ha un valore di ritorno. Se non specificato è il valore di ritorno dell'ultima istruzione eseguita:

 sub miafunzione
 {
     my $x=print "ciao mondo\n";
     print "x=$x\n";
 }                                            

 if ( miafunzione() )
 {
     print "Questa funzione è vera!\n";
 }

che produrrà :

ciao mondo
x=1
Questa funzione è vera!

quindi un valore equiparabile ad un true.

Se si vuole invece specificare un valore allora useremo return :

 sub miafunzione
 {
     my %x=("pippo" , "questo e' pippo" , "pluto" , "questo e' pluto");
     return %x;
 }       

 my %k=miafunzione();

 while ( ( $c , $v ) = each ( %k ) )
 {
     print "chiave=$c , valore=$v\n";
 }

che produrrà :

chiave=pluto , valore=questo e' pluto
chiave=pippo , valore=questo e' pippo


Vediamo ora questo fenomeno:

sub miafunzione
 {
     my %x=("pippo" , "questo e' pippo" , "pluto" , "questo e' pluto");
     return 1 , "nessun errore" , %x;
 }       

 my ( $s , $m , %x ) = miafunzione();
 print "esito : $s , messaggio: $m\n";

 while ( ( $c , $v ) = each ( %x ) )
 {
     print "chiave=$c , valore=$v\n";
 }

che produrrà :

esito : 1 , messaggio: nessun errore
chiave=pluto , valore=questo e' pluto
chiave=pippo , valore=questo e' pippo

Il ritorno a seconda del contesto[modifica]

Se assegniamo il valore di ritorno di una funzione ad una variabile scalare avremo un "contesto" scalare. Se assegniamo il valore di ritorno di una funzione ad una variabile array/hash (lista) avremo un "contesto" lista.

Il contesto non vincola la funzione ma consente al programmatore di diversificare il valore di ritorno. Quindi in un contesto lista il programmatore si aspetta che la funzione ritorni più argomenti, mentre in un contesto scalare il programmatore si aspetta che la funzioni torni un unico valore.

Per diversificare si usa la funzione wantarray che vale 1 se il contesto in cui è valutata la funzione in uso è una lista.

Vediamo l'esempio

 sub estrazione
 {
    if ( wantarray )
    {
        return 3 , 5, 7, 9;
    }
    else
    {
        return 3;
    }
 }

 my $a = estrazione();
 my @b = estrazione();

 print "a=$a\n";
 print "b:".join(" , ",@b)."\n";

che produce:

a=3
b:3 , 5 , 7 , 9

Identificare una funzione[modifica]

Il Perl ha un simbolo per identificare una funzione ed è il "&".Questo simbolo alla versione 5.6.xx non è più utilizzato per le chiamate dirette ma è rimasto per compatibilità con il passato. Quindi si può trovare la chiamata a funzione anche come:

my $a = &estrazione();
my @b = &estrazione();

L'uso di questo simbolo è obbligatorio per far comprendere al linguaggio come utilizzare una variabile quando si vuole che questa si comporti come una funzione. Per chiarimenti proseguire con la lettura.

Funzione anonima[modifica]

Precedentemente alle variabili si è visto come è possibile assegnare diverse cose. Fra queste ci sono anche le funzioni:

 my $fun = sub 
 {
    if ( wantarray )
    {
        return 3 , 5, 7, 9;
    }
    else
    {
        return 3;
    }
 }

 my $f   = &$fun();
 my @fun = &$fun();

 print "f=$f\n";
 print "array fun:".join(" , ",@fun)."\n";

Da notare che non c'è il nome dopo sub e che il nome "nell'uso" è stato sostituito dal nome della variabile (con il $ davanti !)

Una Funzione puntando al nome[modifica]

Guardiamo ora questo codice:

 sub estrazione
 {
    if ( wantarray )
    {
        return 3 , 5, 7, 9;
    }
    else
    {
        return 3;
    }
 }

 my $f = \&estrazione;

 my $a = &$f();
 my @b = &$f();

Quindi in questo modo si è sostituito il "nome" della funzione con la variabile $f. Prestate molta attenzione alla sintassi. Infatti $f viene assegnato un reference "\" alla funzione "&" chiamata "estrazione". Ben diverso è una chiamata, così fatta:

 my $f = \&estrazione();

Infatti in questo caso verrà interpretato come: $f viene assegnato un reference "\" al valore di ritorno della funzione "&" chiamata "estrazione" con parametri nulli. Infatti &estrazione() da luogo alla chiamata della funzione così come &$f(). Mentre \&estrazione fa solo un riferimento ma non invoca la funzione.

 print "a=$a\n";
 print "b:".join(" , ",@b)."\n";

Dato che $f è una variabile è possibile usarla come un reference (infatti lo è), pertanto è possibile usare la sintassi -> :

 my $a = $f->();
 my @b = $f->();

Funzioni con ritorno a funzione (nome o anonima)[modifica]

Questo caso è alquanto raro, tuttavia è interessante per capire cosa avviene, in quanto rappresenta una possibilità offerta dal linguaggio Perl. Se si torna una funzione poi questa deve essere lanciata per poter ottenere un risultato. Vediamo ora questo codice:

 sub estrazione                
 {
    my $num = shift;                              
    $num1 = int ( ( $num * 13 ) / 7 ) % 9 ;       
    $num2 = int ( ( $num * 3  ) / 7 ) % 9 ;       
    my @n = ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 );     
    if ( wantarray )                              
    {                                             
        return $n[$num1], $n[$num2];              
    }                                             
    else                                          
    {                                             
        return $n[$num1];                         
    }                                             
 }                                                
                                                  
 sub controlla
 {                                                 
    my $n;                                        
    foreach $n ( @v )                             
    {                                             
       print "con $num vinto!\n"  if ( $n == 0 ); 
    }                                             
 }                                                 

 sub estrai                                                                
 {                                                                         
    my $num = shift;                                                      
    @v = estrazione($num);                                                
    return sub                                                            
    {                                                                     
        my @altrinum=@_;                                                  
        my $n;
        my $cong="";                                                            
        foreach $n ( @v )                                                 
        {                                                                 
           $cong = " anche" , print "con $num vinto!\n"  if ( $n == 0 );                     
        }                                                                 
        foreach $n ( @altrinum )                                          
        {                                                                 
           print "con $n vinto".$cong." il premio di consolazione!\n"  if ( $n == 0 );
        }                                                                 
    };                                                                    
 }                                                                         

 $a = estrazione (5);                    
 @a = estrazione (5);                    
                                        
 print "a singolo:$a\n";                 
 controlla(5,$a);                        
 print "a array:".join(" , " , @a )."\n";
 controlla(5,@a);                        
                                        
 $a = estrai(5);                         
 print "a singolo:$a\n";                 
 # chiamo la funzione con altri numeri   
 &$a(7,8,0);                             
                                        
 $f = \&estrai;                          
 print "---\n";                                       
 $f ->(6)->(3,0,2);

che produce :

a singolo:0
a array:0 , 2
a singolo:CODE(0x140380)
con 5 vinto!
con 0 vinto anche il premio di consolazione!
---
con 0 vinto il premio di consolazione!

Da notare che nel ritorno della funzione estrai (costituito da un'altra funzione) ci sono dei dati passati durante l' invocazione, che vengono ereditati dalla funzione ritornata. Questo è possibile perché la funzione viene "cablata" con il valore della variabile nel codice della funzione ritornata. Come detto all'inizio è preferibile usare, anche e soprattutto per questioni di manutenzione, le chiamate a funzioni esplicite piuttosto che nella forma anonima/nominale.