Perl/Funzioni

Wikibooks, manuali e libri di testo liberi.


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

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

sub <nome> 
 {
     ... istruzioni ...
 }
 
esempio :
 
 sub miafunzione
 {
     print "ciao mondo\n";
 }
[[Categoria:nome della categoria]]
 miafunzione();

nell'esempio indicato la funzione "miafunzione" non usa parametri.

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

Indice

[modifica] I Parametri

I parametri di una funzione sono delle informazioni necessarie ad una funzione per svolgere il proprio compito.Vengono messi all'interno delle parentesi 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.


[modifica] Il ritorno

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 ( %x ) )
 {
     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


[modifica] Il ritorno a seconda del contesto

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

[modifica] Identificare una funzione

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.

[modifica] Funzione anonima

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 !)

[modifica] Una Funzione puntando al nome

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 a 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 varibile è possibile usarla come un reference (infatti lo è) pertanto è possibile usare la sintassi -> :

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

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

Questo caso è alquanto raro tuttavia è interessante per capire cosa avviene , dato che possibile. 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 nella funzione estrai nel ritorno di funzione ci sono dei dati passati alla prima.Questo è possibile perché la funzione viene "cablata" con il valore della variabile nel codice della funzione ritornata. Come detto all'inizio è preferibile usare ,per la manutenzione, le chiamate a funzioni esplicite che nella forma anonima/nominale.

Strumenti personali