Ciao,
per uscire da un ciclo, puoi usare "Break".
Ci sarebbe anche "Continue" che permette di evitare le righe successive di un ciclo, e di passare all'elemento succecssivo ... almeno credo ... l'ho usato una sola volta, e non ricordo di preciso come funziona ...
Qui comunque la sua descrizione ufficiale: https://www.freepascal.org/docs-html/rtl/system/continue.html
Per quanto riguarda invece i valori di ritorno, di una funzione, quello restituito da "Result", è solo uno. Però se la tua funzione la dichiari ad esempio così:
function ScompattaBasDat(var CodExit:Integer; Applicativo, Versione:String; var DirBase:String):Boolean;
Se valore delle 2 variabili CodExit e DirBase, verrà modificato all'interno della funzione, rimarrà quello anche nel resto del programma. Per le altre 2 variabili, invece non sarà così. La differenza fa il "var " messo prima nella dichiarazione di questi 2 parametri.
Ciao, Mario
Esempio banale di ciclo for con "break" e "continue"
var i, somma: integer;
somma := 0;
for i := 0 to 100 do
begin
if i = 50 then break; //break fà uscire dal ciclo prima anche se doveva ciclare fino a 100
if (i mod 2) > 0 then continue; //continue rimanda al end del for che quindi continua con la prossima iterazione
somma := somma + i; //somma solo i numeri pari
end;
ShowMessage('La somma dei numeri pari da 0 a 49 (a causa del break) è: '+somma.ToString);
Per quello che riguarda i "risultati" delle funzioni, i parametri come ti accennava @bonmario possono essere loro stessi delle variabili IN / OUT.
Però, se ti serve un risultato con molteplici valori sarebbe meglio usare un record:
type TRisultato = record
Risult1: boolean;
Risult2: integer;
Risult3: string;
......
......
end;
var Risultato: TRisultato
function ScompattaBasDat(const CodExit:Integer; const Applicativo, Versione:String; const DirBase:String): TRisultato;
Risultato := ScompattaBasDat(..........);
La parolina "const" inserita nella definizione dei parametri della funzione consente di definire costante quel valore e nella funzione l'assegnazione di un valore al parametro verrà segnalato come errore in fase di compilazione.
Inoltre consente di ottimizzare e velocizzare il codice nella gestione dello stack.
Ciao
2) Forse ricordo male, ma mi pare che era possibile che una funzione restituisse non un solo valore, ma due (o più). Ho fatto ricerche sul web ma sembra che sia possibile restituire un solo valore. E' così?
una funzione restituisce 1 solo valore
tuttavia puoi definire dei parametri "out" così che puoi averne quanti ne vuoi
function TestPositivo(const AValue: integer; out Message: string): boolean;
begin
result := Avalue > 0;
if result then
Message := 'il numero è positivo';
end;
Edit:
https://www.freepascal.org/docs-html/ref/refsu66.html (https://www.freepascal.org/docs-html/ref/refsu66.html)
Giusto per curiosità ho provato a fare girare una funzione con la definizione di OUT nei parametri.
Sia in Delphi che in Lazarus e .... sorpresa il risultato è esattamente lo stesso, ossia funziona esattamente come una VAR (in Delphi non dà alcun avviso ... almeno in Lazarus ti avvisa che forse la variabile non è inizializzata).
Probabilmente le discussioni e le problematiche relative alla gestione delle variabili "managed" (come le string) hanno portato gli sviluppatori dei compilatori a più miti consigli.
Per testare create un applicazione nuova in Lazarus, fate doppio click sulla FORM e poi sovrascrivete TUTTO il codice il seguente, vedrete che la variabile Occhio che vale 5 mantiene il suo valore anche dentro la funzione e al ritorno della funzione vale esattamente come fosse stata definita come VAR.
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs;
type
{ TForm1 }
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
public
end;
function Prova(out tipo: integer): integer;
var
Form1: TForm1;
implementation
{$R *.lfm}
function Prova(out tipo: integer): integer;
begin
result := 0;
result := result + tipo;
tipo := tipo + tipo;
end;
procedure TForm1.FormCreate(Sender: TObject);
var occhio: integer;
begin
Occhio := 5;
ShowMessage(Prova(occhio).ToString+' / '+Occhio.ToString);
end;
end.
Grazie per le risposte, che esaminerò con calma e gesso. Tuttavia...
Tuttavia, forse mi sono espresso male. Per "uscire da una funzione" intendevo proprio abbandonare la funzione in uno o più punti e NON uscire da un semplice ciclo posto all'interno di una funzione.
A livello puramente schematico intendo questo:
Funzione (Mio_Calcolo): String
Begin
Begin
Inizia primo calcolo
Se succede questo, alla fine vai al secondo calcolo
altrimenti EXIT dalla funzione
end;
Begin
Inizia secondo calcolo
Se succede quest'altro, alla fine vai al terzo calcolo
altrimenti EXIT dalla funzione
end;
Begin
Inizia terzo calcolo
Se succede quest'altro ancora, vai alla fine
altrimenti EXIT dalla funzione
end;
Mio_Calcolo:= 'Ecco i risultati:' // Risultati elaborati dalla funzione se tutto è OK
End;
Vi anticipo che, prima che leggessi le vostre risposte, avevo già scritto un programma del tipo indicato, inserendo EXIT in più punti, e funziona!
Il mio dubbio era se quell'Exit possa provocare un evento ricorsivo, che prima o poi degenera in errore.
Ricordo che nel Commodore64(!!) era facile distrarsi e fare un errore del genere:
100 GoSub 200
200 GoTo 100
OUT OF DATA ERROR // Mi pare che - a causa dell'esaurimento dello stack, ci fosse una segnalazione simile, non ricordo di preciso
Ciao,
io "Exit" lo uso il meno possibile.
Il motivo è semplice: supponi che all'inizio della funzione crei un oggetto, e lo distruggi alla fine.
Se in mezzo fai una Exit, l'oggetto rimane in memoria.
Io preferisco usare una booleana, che inizializzo a false, Valorizzo a True quando serve, e condiziona tutti i blocchi.
Il tuo esempio diventerebbe così:
Funzione (Mio_Calcolo): String
Funzione (Mio_Calcolo): String
var VFEsci:Boolean = False;
Begin
if (not VFEsci) then Begin
Inizia primo calcolo
Se succede questo, alla fine vai al secondo calcolo
altrimenti VFEsci:=True
end;
if (not VFEsci) then Begin
Inizia secondo calcolo
Se succede quest'altro, alla fine vai al terzo calcolo
altrimenti VFEsci:=True
end;
if (not VFEsci) then Begin
Inizia terzo calcolo
Se succede quest'altro ancora, vai alla fine
altrimenti VFEsci:=True
end;
Mio_Calcolo:= 'Ecco i risultati:' // Risultati elaborati dalla funzione se tutto è OK
End;
... Se crei qualcosa di locale dentro la funzione, devi distruggerla prima dell'uscita...
Il problema è proprio questo! Per quello che ricordo (dal Visual Basic) era possibile - prima di uscire - "chiudere" un ciclo For...Next assegnando alla variabile il valore finale del For.
Con Lazarus questo non si può fare (a meno che mi sia sfuggito qualcosa) perché impedisce di alterare il valore della variabile responsabile del ciclo.
Per non annoiare, credo cle lo screenshot chiarisca il concetto. La routine è la quarta parte di una funzione suddivisa in sei blocchi (che funziona perfettamente!).
Ovviamente la cancellazione di EsaminaCarattereStringa:=Lenght(Stringa) non interrompe il programma, però quell'Exit (IMHO) rimane "appeso". Che succede se la funzione viene richiamata un numero eccessivo di volte?
Begin
ContaVirgole:=0;
For EsaminaCarattereStringa :=1 to Length(Stringa) do
Begin
CarattereSottoEsame:= Copy(Stringa,EsaminaCarattereStringa,1);
If CarattereSottoEsame ='+' then // Verifica presenza superflua del segno +
Begin
Verifica_Input_Numerico:= Operatore + ': Segno + inutile: eliminare!';
Exit;
end
else
If CarattereSottoEsame = ',' Then
Begin
ContaVirgole:= ContaVirgole +1;
end;
If ContaVirgole > 1 then
Begin
Verifica_Input_Numerico:= Operatore + ': Troppe virgole!';
Exit;
End
Else
End;
End;
vorrei ricordare l'uso di try...finally
l'istruzione exit fa saltare l'esecuzione al blocco delle istruzioni dopo la finally
utilizzando questo modo, non bisogna preoccuparsi del fatto che la exit possa lasciare in uso delle risorse
io lo uso spesso ed è sicuro
esempio:
function TestPariPositivo(const AValue: integer): boolean;
var sl: TStringList;
begin
result:=false;
// alloca risorse
sl:=TStringList.Create;
try
// si esce, destinazione... finally
if AValue <= 0 then
exit;
// elaborazione
result := (AValue mod 2) = 0;
sl.Add('Numero inserito');
sl.Add(AValue.ToString);
sl.Add(result.ToString);
ShowMessage(sl.Text);
finally
// libera risorse
sl.Free;
end;
end;