数组追加 delphi
array append in delphi
我正在尝试在 Delphi 7 中实现数组追加,因为标准库没有它。这是我目前所拥有的,但是当我尝试获取数组的长度时它会抱怨类型不兼容。
procedure ArrayAppend(var GenericArray; const Element);
var
len: Integer;
begin
len := Length(GenericArray);
SetLength(GenericArray, len+1);
GenericArray[len] := Element;
end;
我正在尝试查找 Delphi 7 中最通用的数组类型。
如果这是唯一的方法,我也没有问题返回修改后的数组。
为了说明 Rob Kennedy 在评论中所说的话,这里有一个函数可以将值附加到动态数组。然而,这是一个相当残缺的功能,因为它不支持托管类型。所以你不能有字符串、接口、变体或动态数组。或者确实包含任何托管类型的复合结构。
{$APPTYPE CONSOLE}
uses
SysUtils,
TypInfo;
type
PDynArrayTypeInfo = ^TDynArrayTypeInfo;
TDynArrayTypeInfo = packed record
kind: Byte;
name: Byte;
elSize: Longint;
elType: ^PDynArrayTypeInfo;
varType: Integer;
end;
function DynArraySize(a: Pointer): Integer;
asm
TEST EAX, EAX
JZ @@exit
MOV EAX, [EAX-4]
@@exit:
end;
type
TIntegerArray = array of Integer;
procedure AppendUnmanaged(var arr{: TArray<T>}; const Value{: T}; TypeInfo: PTypeInfo);
var
len, elSize: Integer;
begin
len := DynArraySize(Pointer(arr)) + 1;
DynArraySetLength(Pointer(arr), TypeInfo, 1, @len);
inc(PAnsiChar(TypeInfo), PDynArrayTypeInfo(TypeInfo).name);
elSize := PDynArrayTypeInfo(TypeInfo).elSize;
Move(Value, (PAnsiChar(Pointer(arr)) + (len-1)*elSize)^, elSize);
end;
procedure Main;
var
arr: TIntegerArray;
i, Value: Integer;
begin
Value := -1;
AppendUnmanaged(arr, Value, TypeInfo(TIntegerArray));
Value := 666;
AppendUnmanaged(arr, Value, TypeInfo(TIntegerArray));
Value := 42;
AppendUnmanaged(arr, Value, TypeInfo(TIntegerArray));
for i := low(arr) to high(arr) do
Writeln(arr[i]);
end;
begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
与现代 Delphi 相比,您可以看到一些明显的问题,现代 Delphi 语言中包含泛型和数组连接。具体来说,我在考虑这些问题:
- 您必须为函数提供类型信息。
- 您不能传递文字,因为它们作为无类型参数是无效的。
现在,肯定可以复制编译器在分配托管类型时所做的工作。但这真的值得吗?上面的代码,尤其是调用代码,真的是对类型安全替代方案的改进吗?我个人不这么认为。
我正在尝试在 Delphi 7 中实现数组追加,因为标准库没有它。这是我目前所拥有的,但是当我尝试获取数组的长度时它会抱怨类型不兼容。
procedure ArrayAppend(var GenericArray; const Element);
var
len: Integer;
begin
len := Length(GenericArray);
SetLength(GenericArray, len+1);
GenericArray[len] := Element;
end;
我正在尝试查找 Delphi 7 中最通用的数组类型。
如果这是唯一的方法,我也没有问题返回修改后的数组。
为了说明 Rob Kennedy 在评论中所说的话,这里有一个函数可以将值附加到动态数组。然而,这是一个相当残缺的功能,因为它不支持托管类型。所以你不能有字符串、接口、变体或动态数组。或者确实包含任何托管类型的复合结构。
{$APPTYPE CONSOLE}
uses
SysUtils,
TypInfo;
type
PDynArrayTypeInfo = ^TDynArrayTypeInfo;
TDynArrayTypeInfo = packed record
kind: Byte;
name: Byte;
elSize: Longint;
elType: ^PDynArrayTypeInfo;
varType: Integer;
end;
function DynArraySize(a: Pointer): Integer;
asm
TEST EAX, EAX
JZ @@exit
MOV EAX, [EAX-4]
@@exit:
end;
type
TIntegerArray = array of Integer;
procedure AppendUnmanaged(var arr{: TArray<T>}; const Value{: T}; TypeInfo: PTypeInfo);
var
len, elSize: Integer;
begin
len := DynArraySize(Pointer(arr)) + 1;
DynArraySetLength(Pointer(arr), TypeInfo, 1, @len);
inc(PAnsiChar(TypeInfo), PDynArrayTypeInfo(TypeInfo).name);
elSize := PDynArrayTypeInfo(TypeInfo).elSize;
Move(Value, (PAnsiChar(Pointer(arr)) + (len-1)*elSize)^, elSize);
end;
procedure Main;
var
arr: TIntegerArray;
i, Value: Integer;
begin
Value := -1;
AppendUnmanaged(arr, Value, TypeInfo(TIntegerArray));
Value := 666;
AppendUnmanaged(arr, Value, TypeInfo(TIntegerArray));
Value := 42;
AppendUnmanaged(arr, Value, TypeInfo(TIntegerArray));
for i := low(arr) to high(arr) do
Writeln(arr[i]);
end;
begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
与现代 Delphi 相比,您可以看到一些明显的问题,现代 Delphi 语言中包含泛型和数组连接。具体来说,我在考虑这些问题:
- 您必须为函数提供类型信息。
- 您不能传递文字,因为它们作为无类型参数是无效的。
现在,肯定可以复制编译器在分配托管类型时所做的工作。但这真的值得吗?上面的代码,尤其是调用代码,真的是对类型安全替代方案的改进吗?我个人不这么认为。