简体   繁体   English

我可以定义不同类型的数组类型吗?

[英]Can I define an array type of different types?

I'd like to define an array type which consists of different types, such as String , Integer , Boolean , Double , etc. but no objects, structures, or anything of that nature.我想定义一个由不同类型组成的数组类型,例如StringIntegerBooleanDouble等,但没有对象、结构或任何类似性质的东西。 Then I'd like to use this type as a function argument, for example...然后我想将此类型用作 function 参数,例如...

type
  TMyArray = array of ...?...;

function GetSomething(const Input: TMyArray): String;
var
  X: Integer;
begin
  for X:= 0 to Length(Input) - 1 do begin
    //Identify type and handle accordingly...
    //Serialize data for the result...

  end;
end;

and use it like...并像...一样使用它

Variable:= GetSomething(['some string', 123, 'something else', 12.3, false]);

Then, how do I identify what type each element is when iterating through such an array?那么,在遍历这样的数组时,如何识别每个元素是什么类型呢?

I'm pretty sure this is possible, but have no idea even what terminology to search for.我很确定这是可能的,但甚至不知道要搜索什么术语。 How do I do this?我该怎么做呢?

Would I have to define this as an array of Variants?我必须将其定义为变体数组吗? Or is there a way to define exactly which types the array accepts?或者有没有办法准确定义数组接受的类型?

EDIT编辑

Not to change the question any, but after the answer by RRUZ, I found an intriguing article about the performance when doing this exact thing different ways...不改变任何问题,但在 RRUZ 回答之后,我发现了一篇有趣的文章,介绍了以不同方式做这件事时的性能......

If your Delphi version supports RTTI, you can use an array of TValue and the Kind property like so. 如果您的Delphi版本支持RTTI,您可以使用TValue数组和Kind属性。

{$APPTYPE CONSOLE}


uses
  System.TypInfo,
  System.Rtti,
  System.SysUtils;


function GetSomething(const Input: array of TValue): String;
var
  X: Integer;
  LValue : TValue;
begin
  for LValue in Input  do begin
     case LValue.Kind of
       tkUnknown: Writeln('Unknown');
       tkInteger:  Writeln(Format('The Kind of the element is Integer and the value is %d',[LValue.AsInteger]));
       tkChar: Writeln('Char');
       tkEnumeration: if LValue.TypeInfo=TypeInfo(Boolean) then Writeln(Format('The Kind of the element is Boolean and the value is %s',[BoolToStr(LValue.AsBoolean, True)]));
       tkFloat: Writeln(Format('The Kind of the element is Float and the value is %n',[LValue.AsExtended]));
       tkString: Writeln('String');
       tkSet: Writeln('Set');
       tkClass: Writeln('Class');
       tkMethod:Writeln('method');
       tkWChar: Writeln('WChar');
       tkLString: Writeln('String');
       tkWString: Writeln('String');
       tkVariant: Writeln('Variant');
       tkArray: Writeln('Array');
       tkRecord: Writeln('Record');
       tkInterface: Writeln('Interface');
       tkInt64: Writeln('Int64');
       tkDynArray: Writeln('DynArray');
       tkUString:  Writeln(Format('The Kind of the element is String and the value is %s',[LValue.AsString]));
       tkClassRef:  Writeln('Class Ref');
       tkPointer: Writeln('Pointer');
       tkProcedure:  Writeln('procedure');
     end;
  end;
end;

begin
  try
    GetSomething(['some string', 123, 'something else', 12.3, false]);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

Another option is use an array of const 另一种选择是使用array of const

{$APPTYPE CONSOLE}

uses
  SysUtils;


procedure GetSomething(const Input: array of const);
var
  LIndex: Integer;
begin
  for LIndex := Low(Input) to High(Input) do
  begin
    case Input[LIndex].VType of
      vtWideString: Writeln('WideString = ''', WideString(Input[LIndex].VWideChar), '''');
      vtInt64: Writeln('Int64 = ', Input[LIndex].VInt64^);
      vtCurrency: Writeln('Currency = ', CurrToStr(Input[LIndex].VCurrency^));
      vtInteger: Writeln('Integer = ', Input[LIndex].VInteger);
      vtBoolean: Writeln('Boolean = ', BoolToStr(Input[LIndex].VBoolean, True));
      vtChar: Writeln('Char = ''', Input[LIndex].VChar, '''');
      vtExtended: Writeln('Extended = ', FloatToStr(Input[LIndex].VExtended^));
      vtString: Writeln('ShortString = ''', Input[LIndex].VString^, '''');
      vtPChar: Writeln('PChar = ''', Input[LIndex].VPChar, '''');
      vtAnsiString: Writeln('AnsiString = ''', Ansistring(Input[LIndex].VAnsiString), '''');
      vtWideChar: Writeln('WideChar = ''', Input[LIndex].VWideChar, '''');
      vtPWideChar: Writeln('PWideChar = ''', Input[LIndex].VPWideChar, '''');
      vtUnicodeString : Writeln('UnicodeString = ''', string(Input[LIndex].VUnicodeString), '''');
    else
      Writeln('Unsupported');
    end;
  end;
end;

begin
  try
    GetSomething(['some string', 123, 'something else', 12.3, false]);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

Oddly enough, nobody has yet mentioned variant records, which have been a feature of Pascal for decades: 奇怪的是,没有人提到变体记录,这几十年来一直是Pascal的一个特征:

type
  TVarRecType = (vrtInteger, vrtDouble {other types go here});
  TVarRec = record
    Field1: string; { can be omitted }
  case RecType: TVarRecType of
    vrtInteger:
      IntValue: integer;
    vrtDouble:
      DblValue: double;
    { other cases go here }
  end;

var
  VarRec: TVarRecType;
begin
  VarRec.Field1 := 'This is an example.';
  VarRec.RecType := vrtInteger;
  VarRec.IntValue := 4711;
  {...}
  VarRec.RecType := wrtDouble;
  VarRec.DblValue := Pi;
  {...}
end;

{ Oops, forgot the array part }
type
  TVarRecArr = array[1..15] of TVarRec;
var
  VarRecArr: TVarRecArr;
begin
  VarRecArr[1].Field1 := 'This is the first record';
  VarRecArr[1].RecType := wrtInteger;
  VarRecArr[1].IntValue := 1;
  {...}
end;

Arrays are homogeneous. 阵列是同质的。 As the documentation says: 正如文件所说:

An array represents an indexed collection of elements of the same type (called the base type). 数组表示相同类型的元素的索引集合(称为基类型)。

Therefore you can achieve your goal only by way of a base type that can hold differing types of data. 因此,您只能通过可以容纳不同类型数据的基本类型来实现您的目标。 Such a data type is known as a variant data type . 这种数据类型称为变体数据类型

In Delphi there are a number of possibilities for variant data types. 在Delphi中,变体数据类型有很多种可能性。 There is the venerable COM Variant type. 有令人尊敬的COM Variant类型。 There is the new kid on the block, TValue , which was added to support new style RTTI. 有一个新的孩子, TValue ,它被添加以支持新式RTTI。 And there are many third party options. 还有很多第三方选择。 Typically these third party options exist to support persistence frameworks. 通常,这些第三方选项可用于支持持久性框架。

Since is for use as an parameter, you could use the array of const construct. 由于是用作参数,因此可以使用array of const构造的array of const Also known as variant open array parameters . 也称为变量开放数组参数 More on my answer on this other question . 更多关于我对这个问题的回答

It works like your desired array of different types. 它的工作方式与所需的不同类型数组相同。 Delphi docwiki documentation on that theme 关于该主题的Delphi docwiki文档

It's really easy and it's not different between Delphi's versions这真的很容易,而且Delphi的版本之间没有什么不同

first you need to a record of name and type such as this:首先,您需要记录名称和类型,例如:

Customer = record
OINTCUSTID      : INTEGER ;
CUSTTYPE        : SmallInt;
NAME            : string[30];
end;

and now different your array like this:现在像这样改变你的数组:

Glb_CUSTOMER       :ARRAY [1..20] OF Customer;

Now you have an array with different type.现在你有一个不同类型的数组。

Assuming that in the end you want to get the output of the array as a string (with the procedure GetSomething ).假设最后您想将数组的 output 作为字符串获取(使用过程GetSomething )。 I think you can easily do this using Variants .我认为您可以使用Variants轻松做到这一点。
Define your array like this:像这样定义你的数组:

MyArray = array of variant;

The GetSomething procedure now is simple: GetSomething procedure现在很简单:

function TForm3.GetSomething(const Input: TMyArray): String;
var
  X: Integer;
begin
  for X:= 0 to Length(Input) - 1 do
    //Identify type and handle accordingly...
    //Serialize data for the result...
    Result := Result + VarToStrDef(Input[X], '?') + ' | ';
end;

And the result is the expected.结果是预期的。
This line:这一行:

Variable:= GetSomething(['some string', 123, 'something else', 12.3, false]);

Return this result:返回这个结果:

some string |一些字符串 | 123 | 123 | something else |别的东西 | 12,3 | 12,3 | False |错误 |

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM