Ciao a tutti,
faccio una domanda che, forse, potrebbe essere interessante. Come si a passare un array of string in una funzione che accetta array of const in maniera semplice.
Ad esempio :
program Project1;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
Classes, sysutils
{ you can add units after this };
procedure caio(par : array of const);
begin
end;
var
pp : TStringArray;
begin
pp := TStringArray.Create('rrr', 'rrre', 'www', 'eeee');
caio (pp); // <- non funziona
end.
Avevo trovato con TVarRec ma è lunga da fare. Esiste un modo più semplice?
A livello di compilazione "array of const" è equivalente ad "array of TVarRec" come ha accennato @nomorelogic.
La gestione è un pò più complicata di un tipo variant, ma di fatto non molto di più se si pensa che si stanno usando tipi "a caso" in un array ...
procedure TForm1.Prova(tip: array of const);
var i: TVarRec;
begin
for i in tip do
begin
if (i.VType = VTInteger) then
ShowMessage(inttostr(i.VInteger));
if (i.VType = vtAnsiString) then
ShowMessage(String(i.VAnsiString));
if (i.VType = vtExtended) then
ShowMessage(floattostr(Double(i.VExtended^)));
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var p: integer;
a: string;
b: double;
begin
p := 10;
a := 'Pollo arrosto';
b := 234.87;
Prova([p,a,b]);
end;
Occhio ai tipi, ad esempio il tipo VtAnsiString o VtExtended potrebbero essere diversi in realtà o "rappresentare" dati diversi: ad esempio se il progetto è impostato come UNICODE, i tipi string non sono più AnsiString ma diventano Unicode e quindi ciò che abbiamo scritto và implementato anche con VtUnicode ... il tipo VtExtended può rappresentare anche un valore di tipo single e quindi quando faccio il casting sul VExtended devo fare attenzione, ad esempio dovrei controllare la lunghezza del dato in modo da identificarlo tra single e double.
Occhio che usare una tale codifica potrebbe esporre il codice a certe e sicure anomalie in futuro, difficili poi da analizzare.
Con tutta sincerità, a meno che non sia indispensabile io non userei "array of const" per alcun motivo, come non userei TVarRec in quanto fortemente dipendente dalla versione del compilatore.
L'uso di array "aperti" con dati misti dovrebbe essere evitato il più possibile, a meno che i dati non siano a priori certi e noti (ad esempio: sicuramente double, interi e stringhe UNICODE).
Bye
faccio una domanda che, forse, potrebbe essere interessante. Come si a passare un array of string in una funzione che accetta array of const in maniera semplice.
Per venire alla tua domanda specifica dopo la dissertazione del post precedente , purtroppo in Lazarus non sono riuscito a fare funzionare ciò che dovrebbe essere logicamente funzionante e banale, ossia l'associazione tra tipi.
Il seguente codice funziona in Delphi ma non c'è modo di farlo funzionare in Lazarus, neanche usando i puntatori ... sicuramente sono io che sbaglio qualcosa ...
EDIT: usando il puntatore a tipo invece di un puntatore puro risolve la situazione in Lazarus.
type
TMioArray = array of string;
PTMioArray = ^TMioArray;
procedure TForm1.Prova(tip: array of const);
var i: TVarRec;
punta: pointer;
s: string;
begin
for i in tip do
begin
if (i.VType = VtInteger) then
ShowMessage(inttostr(i.VInteger));
if (i.VType = VtAnsiString) then //In Lazarus deve essere usato AnsiString, in Delphi invece UnicodeString
ShowMessage(String(i.VAnsiString));
if (i.VType = VtPointer) then
begin
punta := PTMioArray(i.VPointer);
for s in TMioArray(punta) do
ShowMessage(s);
end;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var p: integer;
a: string;
b: double;
ar: TMioArray;
begin
p := 10;
a := 'Pollo arrosto';
b := 234.87;
setlength(ar, 2);
ar[0] := 'Pippo';
ar[1] := 'Pluto';
Prova([PTMioArray(ar), p, a, b]);
// Prova([ar, p, a, b]); //<--- Questo funziona solo in Delphi, In Lazarus si deve usare un "puntatore a ar" al posto di ar ... non usare @ar !!!!
end;
Si può usare anche con lo TStringArray ovviamente, ma bisogna usare il puntatore specializzato comunque:
type
TMioArray = array of string;
PTMioArray = ^TMioArray;
procedure TForm1.Prova(tip: array of const);
var i: TVarRec;
punta: pointer;
s: string;
begin
for i in tip do
begin
if (i.VType = VtInteger) then
ShowMessage(inttostr(i.VInteger));
if (i.VType = VtAnsiString) then //In Lazarus deve essere usato AnsiString, in Delphi invece UnicodeString
ShowMessage(String(i.VAnsiString));
if (i.VType = VtPointer) then
begin
punta := PTMioArray(i.VPointer);
for s in TMioArray(punta) do
ShowMessage(s);
end;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var p: integer;
a: string;
b: double;
ar: TMioArray;
strar: TStringArray;
begin
p := 10;
a := 'Pollo arrosto';
b := 234.87;
setlength(ar, 2);
ar[0] := 'Pippo';
ar[1] := 'Pluto';
strar := TSTringArray.Create('rrr', 'rrre', 'www', 'eeee');
Prova([PTMioArray(strar), PTMioarray(ar), p, a, b]);
// Prova([PTMioarr(ar), p, a, b]);
// Prova([pp, p, a, b]); //<--- Questo funziona solo in Delphi, In Lazarus si deve usare un "puntatore a ar" al posto di ar ... non usare @ar !!!!
end;
La definizione di TVarRec definisce le seguenti tipologie di tipi:
const
vtInteger = 0;
vtBoolean = 1;
vtChar = 2;
vtExtended = 3;
vtString = 4;
vtPointer = 5;
vtPChar = 6;
vtObject = 7;
vtClass = 8;
vtWideChar = 9;
vtPWideChar = 10;
vtAnsiString = 11;
vtCurrency = 12;
vtVariant = 13;
vtInterface = 14;
vtWideString = 15;
vtInt64 = 16;
vtQWord = 17;
vtUnicodeString = 18;
Per qualsiasi ulteriore tipo (come negli esempi sopra, un'array) viene usato il VtPointer.
Nei variant (TVarType) sono invece identificati questi tipi, in più ci sono una serie di routine che aiutano a runtime a definire ulteriori caratteristiche del variant (ad esempio IsVarArray).
varEmpty = 0;
varNull = 1;
varSmallInt = 2;
varInteger = 3;
varSingle = 4;
varDouble = 5;
varDate = 7;
varCurrency = 6;
varOleStr = 8;
varDispatch = 9;
varError = 10;
varBoolean = 11;
varVariant = 12;
varUnknown = 13;
varDecimal = 14;
varShortInt = 16;
varByte = 17;
varWord = 18;
varLongWord = 19;
varInt64 = 20;
varQWord = 21;
EDIT: a livello di curiosità, il costrutto "array of const" è quello usato ad esempio nella definizione della funzione Format che se fate presente viene usata allo stesso modo degli esempi riportati sopra:
Format('%d - %s - %f', [p, a, b]);