Delphi 复制动态数组

Delphi 复制动态数组

Delphi 的动态数组使用很方便,支持自动管理内存,无需显式释放;其实质是指向连续内存的智能指针。既然是指针,直接赋值就会导致两个变量指向同一个数组,如果修改其中一个,另一个也会改变。例如:

var
  a, b: array of Integer;
begin
  SetLength(a, 2);
  a[0] := 1;
  a[1] := 2;
  // 此时 a 为 [1,2]
  b := a;
  b[1] := 3;
  // 此时 a, b 皆为 [1,3]
end;

如果要想把数组复制一份,并且修改其中一个另一个不会变动,就要复制数组的内容。可以写一个这样的方法复制数组。

procedure MyCopyArr(out Dest: array of Integer; const Source: array of Integer);
  Len, i: Integer;
begin
  Len := Length(Source);
  SetLength(Dest, Len);
  for i := 0 to Len - 1 do
    Dest[i] := Source[i];
end;

但是,这样会报错: E2008 Incompatible types 。这是因为单独写一个 array of Integer 相当于声明一个新类型,在不同地方出现的 array of Integer 是不能相容的。

一种解决方法是定义类型名:

type
  TIntArr = array of Integer;

这样使用 TIntArr 代替 array of Integer 就不会报错。但是每次都要声明一个新类型很麻烦,毕竟懒惰是程序员的第一动力。Delphi 早就想好了应对方法,在 System 单元中有一个隐藏的声明:

type
  TArray<T> = array of T;

这是 Delphi 泛型的语法,了解 C++ 的 template 的同学应该能理解。如此,就可以用 TArray<Integer> 代替 array of Integer ,也不会出现编译器报错。

另外,Delphi 也内置了一个复制动态数组的方法 Copy 。它不只可以复制整个数组,也可以复制数组的一部分。举个栗子:

var
  a, b: TArray<Integer>; // 这里写成 array of Integer 不会报错,因为 a 和 b 的声明是简写在一起的。
  // 如果写成 a: array of Integer; b: array of Integer; 就会报错。
begin
  SetLength(a, 2);
  a[0] := 1;
  a[1] := 2;
  // 此时 a 为 [1,2]