Differenze tra le versioni di "Scrivere una Funzione"
Riga 338: | Riga 338: | ||
− | '''Private''' Function Funzione_Chiamata(<FONT Color=#B22222>ByRef</font> aRif As Integer, bI As Integer) | + | '''Private''' Function Funzione_Chiamata(<FONT Color=#B22222>ByRef</font> aRif As Integer, bI As Integer) |
Dim somma As Integer | Dim somma As Integer |
Versione delle 12:48, 16 mag 2015
Una Funzione |1| |2| è una routine, chiamata da una routine principale, alla quale è delegato il compito di svolgere una serie di operazioni, e delle quali essa restituisce alla routine principale chiamante il risultato.
Poiché una funzione deve eseguire un compito, si ritiene non opportuno scrivere una funzione per eseguire più istruzioni insieme. E' preferibile scrivere funzioni per singoli compiti ed una ulteriore funzione che svolga l'operazione complessa, invocando le funzioni precedenti.
La funzione informatica converte argomenti di un determinato insieme in un valore di ritorno di un altro determinato insieme.
Indice
Passaggio dei valori ad una Funzione
La routine principale chiamante può passare attraverso i suoi argomenti uno o più valori alla Funzione chiamata. Il passaggio degli argomenti ad una Funzione può essere di tre tipi:
- per valore;
- per indirizzo;
- per riferimento.
Passaggio per valore
Il passaggio per valore è senz'altro la modalità più frequente di passare dei dati ad una Funzione chiamata.
Con il passaggio per valore viene effettuata una copia della variabile passata alla Funzione chiamata come argomento della routine principale chiamante. Inoltre, le modifiche alla variabile del parametro passato, effettuate nella Funzione chiamata, restano confinate nell'ambito locale di detta Funzione secondaria. Ciò significa che la variabile, passata precedentemente come parametro dalla routine chiamante a quella chiamata, non vede modificarsi il suo valore, nonostante la sua copia abbia subito una modifica del proprio valore a seguito di una o più operazioni nella Funzione secondaria chiamata.
Se, dunque, non vi fosse ritorno di valore della varibile-copia, ora con valore modificato, alla routine principale chiamante, non sarebbe possibile utilizzare le modifiche apportate dalle operazioni alle quali la Funzione secondaria chiamata è stata preposta.
Mostriamo un semplice esempio:
Public Sub Main() ' Routine principale Dim a, b, risultato_di_ritorno As Integer a = 2 b = 3 ' Chiama la Funzione, e le passa i due valori, affinché li elabori. ' Alla fine la Funzione restituirà il risultato che riempirà la variabile integer "risultato_di_ritorno": risultato_di_ritorno = funzione_chiamata(a, b) ' Mostriamo il risultato in console: Print "Risultato di ritorno dalla funzione = "; risultato_di_ritorno End ' La funzione secondaria "Funzione_Chiamata" contiene il proprio nome ed i parametri come variabili dei valori passati dalla routine chiamante, e non prevede l'aggiunta della parola chiave "Sub". ' Essa, poiché restituisce - in questo nostro esempio - un valore Integer, termina la propria dichiarazione con: " As Integer" . Private Function Funzione_Chiamata(aF As Integer, bF As Integer) As Integer Dim somma As Integer somma = aF + bF '|3| ' Viene restituito il risultato alla routine chiamante: Return somma End
In console avremo coerentemente:
Risultato di ritorno dalla funzione = 5
...e se la Funzione deve restituire due o più risultati ?
Se la Funzione deve restituire più di un risultato non è possibile utilizzare l'istruzione Return, giacché essa restituisce un solo valore.
Per ottenere da una medesima Funzione due o più risultati (quindi senza dover utilizzare una variabile globale), possiamo utilizzare due modalità:
- il passaggio per indirizzo;
- uso di una variabile vettoriale.
Uso di un vettore
Mostriamo un esempio di una Funzione che restituisce un duplice risultato:
Public Sub Main() Dim a, b As Integer Dim risultato_di_ritorno As Integer[] a = 2 b = 3 ' Chiama la Funzione, e le passa i due valori, affinché li elabori. ' Alla fine la Funzione restituirà il risultato che riempirà la variabile vettoriale integer[] "risultato_di_ritorno": risultato_di_ritorno = Funzione_Chiamata(a, b) ' Mostriamo il primo risultato (la somma) in console: Print "Risultato (somma) di ritorno dalla funzione = "; risultato_di_ritorno[0] ' Mostriamo il secondo risultato (la differenza) in console: Print "Risultato (differenza) di ritorno dalla funzione = "; risultato_di_ritorno[1] End ' La routine Funzione, poiché restituisce - in questo nostro esempio - un valore vettore Integer[], termina la propria dichiarazione con: As Integer[]. Public Function Funzione_Chiamata(aF As Integer, bF As Integer) As Integer[] Dim somma, differenza As Integer Dim doppiorisultato As New Integer[] somma = aF + bF differenza = bF - aF ' Nel primo campo dell'array inseriamo il valore contenuto dalla variabile Integer "somma": doppiorisultato.Add(somma) ' Nel secondo campo dell'array inseriamo il valore contenuto dalla variabile Integer "differenza": doppiorisultato.Add(differenza) ' Dunque ora la variabile Integer[] "doppiorisultato" contiene due valori. ' Tale duplice contenuto di questa variabile Integer[] viene restituito alla routine principale chiamante: Return doppiorisultato End
In console avremo coerentemente:
Risultato (somma) di ritorno dalla funzione = 5
Risultato (differenza) di ritorno dalla funzione = 1
Passaggio per indirizzo
Il passaggio per indirizzo, molto simile a quello per riferimento, prevede che la routine principale chiamante passi alla Funzione chiamata argomenti di tipo puntatore. Dunque saranno passati alla Funzione chiamata gli indirizzi di memoria delle variabili della routine chiamante contenenti i valori che dovranno essere gestiti dalle istruzioni della Funzione chiamata.
Affinché i valori delle variabile passate come Puntatori possano essere gestiti dalla Funzione secondaria chiamata, bisognerà preliminarmente dereferenziarli.
Mostriamo un semplice esempio:
Public Sub Main() Dim a, b, risultato As Integer a = 3 b = 5 risultato = Funzione_Chiamata(VarPtr(a), VarPtr(b)) Print risultato End Private Function Funzione_Chiamata(pa As Pointer, pb As Pointer) As Integer Dim ris As Integer ris = Int@(pa) * Int@(pb) Return ris End
Ritorno dei valori per indirizzo attraverso i medesimi parametri delle funzioni
La vera particolarità del passaggio degli argomenti per indirizzo è che tale modalità di passaggio ci consente di eliminare l'istruzione Return, e di ritornare, così, il valore dalla Funzione chiamata alla routine principale chiamante attraverso i parametri medesimi della Funzione.
Per ottenere ciò, per scrivere in uno dei parametri di tipo Puntatore della Funzione chiamata il risultato finale delle operazioni compiute dalla Funzione chiamata, bisognerà utilizzare i Memory Stream:
Public Sub Main() Dim a, b, risultato As Integer a = 3 b = 5 Funzione_Chiamata(VarPtr(a), VarPtr(b)) Print a End Private Function Funzione_Chiamata(pa As Pointer, pb As Pointer) As Integer Dim ris As Integer Dim st As Stream ' Viene creata la variabile "Stream" da una variabile "Puntatore": st = Memory pa For Write ' Scrive all'interno dello "Stream" il risultato dell'operazione: Write #st, Int@(pa) * Int@(pb) As Integer st.Close End
Questa modalità ci consente di ritornare alla routine chiamante anche più valori.
Stesso comportamento quando la variabile da passare sia originariamente un Puntatore:
Public Sub Main() Dim p As Pointer p = Alloc("abcde") Funzione_Chiamata(p) Print String@(p) Free(p) End Private Function Funzione_Chiamata(po As Pointer) Dim st As Stream st = Memory po For Write Write #st, 70 As Byte st.Close End
In quest'altro caso vengono ritornati due valori attraverso i parametri della Funzione !
Public Sub Main() Dim dividendo, divisore As Integer Dim p1, p2 As Pointer Print "Scrivere i valori del dividendo e del divisore." Input dividendo Input divisore p1 = VarPtr(dividendo) p2 = VarPtr(divisore) Funzione_Chiamata(p1, p2) Print "Quoziente: "; Int@(p1) Print "Resto: "; Int@(p2) End Public Function division(divid As Pointer, divis As Pointer) Dim i1, i2, ris As Integer Dim st As Stream i1 = Int@(divid) i2 = Int@(divis) ris = i1 / i2 st = Memory divid For Write Write #st, ris As Integer st.Close ris = i1 Mod i2 st = Memory divis For Write Write #st, ris As Integer st.Close End
Ritorno di valori per indirizzo senza utilizzo come argomento di un esplicito Puntatore
Abbiamo visto nel paragrafo appena precedente che il ritorno di un valore attraverso i parametri (o argomenti) della Funzione prevedeva che il parametro (o i parametri, nel caso si intenda far ritornare più valori) deve essere dichiarato come tipo Puntatore, dato che si tratta di passaggio dell'indirizzo di memoria della variabile, presente nella routine principale, contenente il valore da gestire nella Funzione secondaria chiamata.
Qualora il tipo di argomenti siano una Struttura oppure un vettore, non v'è necessità che i parametri, passati alla Funzione chiamata, siano di tipo Puntatore.
Mostriamo due esempi pratici.
Public Struct STRUTTURA b As Byte s As Short i As Integer End Struct Public Sub Main() Dim st As New STRUTTURA With st .b = 99 .s = 9999 .i = 999999 End With Funzione_Chiamata(st) With st Print .b Print .s Print .i End With End Private Function Funzione_Chiamata(n As STRUTTURA) With n .b += 99 .s += 9999 .i += 999999 End With End
Public Sub Main() Dim ss As String[] = ["a", "b", "c"] Print ss.Count Prova(ss) Print ss.Count End Private Function Prova(vett As String[]) vett.Remove(1) End
Passaggio per Riferimento
Il passaggio per riferimento in Gambas prevede sia nella Funzione chiamante sia nella Funzione chiamata l'uso della parola chiave ByRef prima dell'argomento da passare.
Ovviamente anche questa modalità, come per il passaggio per indirizzo, non necessita dell'uso dell'istruzione Return al termine della Funzione chiamata.
Mostriamo un esempio:
Public Sub Main() Dim a, b As Integer a = 2 b = 3 Funzione_Chiamata(ByRef a, b) Print "Risultato di ritorno dalla funzione = "; a End Private Function Funzione_Chiamata(ByRef aRif As Integer, bI As Integer) Dim somma As Integer ' Si effettua l'operazione fra i due argomenti, ed il risultato viene restituito attraverso il parametro individuato con "ByRef": aRif = aRif * bI End
Scrivere ed invocare una Funzione in un Modulo
La scrittura e la successiva invocazione di una Funzione in un Modulo segue la procedura normale.
Facciamo un semplissimo esempio.
Nella Classe principale avremo il seguente codice:
Public Sub Form_Open() Dim by As Byte ' Invochiamo la funzione nel Modulo e le passiamo un valore di tipo Byte (in questo esempio: 6 ). ' Essa, a sua volta, ci passerà un valore che inseriremo nella variabile "by": by = Module1.funzioneNelModulo(6) Print by End
Nel Modulo avremo:
Public Function funzioneNelModulo(a As Byte) As Byte ' Riceve dalla routine chiamante un valore di tipo "Byte", ed un valore di tipo "Byte" a sua volta restituirà Dim b As Byte b = 2 ' La Funzione effettua l'operazione per la quale è stata concepita: b = b * a ' Restituisce, quindi, alla routine chiamante, presente nella Classe principale, il risultato dell'operazione: Return b End
Note
[1] «La "funzione" di una cosa è ciò che la sola cosa può compiere.» (Platone, La Repubblica)
[2] Si rinvia anche a Wikipedia per una definizione più ampia della Funzione.
[3] La tipologia delle variabili aF e bF è stata già dichiarata all'interno dei parametri della Funzione: (aF As Integer, bF As Integer).
Pagina in costruzione !