首页 > 解决方案 > Delphi - 指向TRecord的const数组?

问题描述

如何让变量指向记录数组?

注意:我希望将 TRecord 的预定义数组作为常量......但是在代码中,我需要变量“W”来记录要使用的记录数组。

请注意,我不希望使用 TRecord 的构造函数在代码中(动态)创建 TRecord 数组,但希望拥有静态数组(因为数据不会改变)。

如何获取变量“W”来“记录”哪个 TRecord 数组?

请参阅下面的代码 - 更容易理解我的意思。

procedure TForm1.Button1Click(Sender: TObject);
type
  TTestRec = record
    X: string;
    Y: Integer;
  end;
  TMyArr = TArray<TTestRec>;
const
  ARRAY_A : TArray<string> = ['A1', 'A2', 'A3', 'A4'];
  ARRAY_B : TArray<string> = ['B1', 'B2', 'B3'];

  ARRAY_C : array[1..2] of TTestRec = (
    (X: 'testC1'; Y:1),
    (X: 'testC2'; Y:2)
    );
  ARRAY_D : array[1..3] of TTestRec = (
    (X: 'testD1'; Y:3),
    (X: 'testD2'; Y:4)
    (X: 'testD3'; Y:9)
    );
var
  Z : TArray<string>;
  W : array of TTestRec;
begin
  Z := ARRAY_A;  // this works
  Z := ARRAY_B;  // this works

  W := ARRAY_C;  // this does not work
  W := ARRAY_D;  // this does not work
end;

标签: arraysdelphiconstantsrecord

解决方案


分配ARRAY_AorARRAY_B有效Z,因为您将TArray<string>常量分配给TArray<string>变量。它们都是同一类型,因此它们相互兼容。

分配ARRAY_Cor ARRAY_DtoW不起作用,因为您将静态数组常量分配给动态数组变量。它们是彼此不兼容的不同类型,如 Delphi 的文档中所述:

类型兼容性和标识 (Delphi)

类型兼容性

每种类型都与自身兼容。如果两种不同的类型至少满足以下条件之一,则它们是兼容的。

  • 他们都是真正的类型。
  • 它们都是整数类型。
  • 一种类型是另一种类型的子范围。
  • 两种类型都是相同类型的子范围。
  • 两者都是具有兼容基本类型的集合类型。
  • 两者都是具有相同字符数的压缩字符串类型。
  • 一种是字符串类型,另一种是字符串、压缩字符串或Char类型。
  • 一种类型是Variant整数、实数、字符串、字符或布尔类型。
  • 两者都是类、类引用或接口类型,一种类型派生自另一种类型。
  • 一种是PAnsiCharor PWideChar,另一种是形式为 or 的从零开始的字符array[0..n] of PAnsiChar数组PWideChar
  • 一种类型是Pointer(无类型指针),另一种是任何指针类型。
  • 两种类型都是(类型化的)指向同一类型的指针,并且{$T+}编译器指令有效。
  • 两者都是过程类型,具有相同的结果类型、相同数量的参数以及对应位置的参数之间的类型标识。

分配兼容性

分配兼容性不是对称关系。如果表达式的值落在 T1 的范围内并且至少满足以下条件之一,则可以将 T2 类型的表达式分配给 T1 类型的变量:

  • T1和T2属于同一类型,不是包含任何级别的文件类型的文件类型或结构化类型。
  • T1 和 T2 是兼容的序数类型。
  • T1 和 T2 都是实数类型。
  • T1 是实数类型,T2 是整数类型。
  • T1 是PAnsiChar、或任何字符串类型PWideCharPChar并且表达式是字符串常量。
  • T1 和 T2 都是字符串类型。
  • T1 是字符串类型,T2 是Char压缩字符串类型。
  • T1 是一个长字符串,T2 是PAnsiChar,PWideCharPChar
  • T1 和 T2 是兼容的打包字符串类型。
  • T1 和 T2 是兼容的集合类型。
  • T1 和 T2 是兼容的指针类型。
  • T1 和 T2 都是类、类引用或接口类型,而 T2 是从 T1 派生的。
  • T1 是接口类型,T2 是实现 T1 的类类型。
  • T1 是PAnsiCharorPWideChar并且 T2 是一个从零开始的字符数组,其形式为array[0..n] of Char(当 T1 为 时PAnsiChar)或WideChar(当 T1 为 时PWideChar)。
  • T1 和 T2 是兼容的过程类型。(在某些赋值语句中,函数或过程标识符被视为过程类型的表达式。参见本章前面的“语句和表达式中的过程类型”。)
  • T1Variant和 T2 是整数、实数、字符串、字符、布尔值、接口类型或OleVariant类型。
  • T1 是一个OleVariant,T2 是一个整数、实数、字符串、字符、布尔值、接口或Variant类型。
  • T1 是整数、实数、字符串、字符或布尔类型,T2 是VariantOleVariant
  • T1 是IUnknownorIDispatch接口类型,T2 是Variantor OleVariant。(如果 T1 是,或者如果T1 是 ,则变体的类型代码必须是varEmpty、或。)varUnknownvarDispatchIUnknownvarEmptyvarDispatchIDispatch

分配ARRAY_AARRAY_B满足Z“分配兼容性”要求。分配ARRAY_CARRAY_D分配W不。

要解决静态数组的问题,您必须改用指针(动态数组已经是指针),例如:

procedure TForm1.Button1Click(Sender: TObject);
type
  TTestRec = record
    X: string;
    Y: Integer;
  end;
  PTestRec = ^TTestRec;
const
  ARRAY_A : TArray<string> = ['A1', 'A2', 'A3', 'A4'];
  ARRAY_B : TArray<string> = ['B1', 'B2', 'B3'];

  ARRAY_C : array[1..2] of TTestRec = (
    (X: 'testC1'; Y:1),
    (X: 'testC2'; Y:2)
    );
  ARRAY_D : array[1..3] of TTestRec = (
    (X: 'testD1'; Y:3),
    (X: 'testD2'; Y:4)
    (X: 'testD3'; Y:9)
    );
var
  Z : TArray<string>;
  W : PTestRec;
begin
  Z := ARRAY_A;
  Z := ARRAY_B;

  W := @ARRAY_C[1];
  W := @ARRAY_D[1];
end;

但是请注意,无法从W自身确定它是指向 anarray[1..2] of TTestRec还是 an array[1..3] of TTestRec,这是两种完全不同的类型。因此,如果您需要使用W来迭代数组,则必须单独跟踪可接受的边界,例如:

{$POINTERMATH ON}

procedure TForm1.Button1Click(Sender: TObject);
type
  TTestRec = record
    X: string;
    Y: Integer;
  end;
  PTestRec = ^TTestRec;
const
  ARRAY_A : TArray<string> = ['A1', 'A2', 'A3', 'A4'];
  ARRAY_B : TArray<string> = ['B1', 'B2', 'B3'];

  ARRAY_C : array[1..2] of TTestRec = (
    (X: 'testC1'; Y:1),
    (X: 'testC2'; Y:2)
    );
  ARRAY_D : array[1..3] of TTestRec = (
    (X: 'testD1'; Y:3),
    (X: 'testD2'; Y:4)
    (X: 'testD3'; Y:9)
    );
var
  Z : TArray<string>;
  W : PTestRec;
  W_Len, I: Integer;
begin
  Z := ARRAY_A;
  for I := 0 to High(Z) do begin
    // use Z[I] as needed ...
  end;

  Z := ARRAY_B;
  for I := 0 to High(Z) do begin
    // use Z[I] as needed ...
  end;

  W := @ARRAY_C[1];
  W_Len := Length(ARRAY_C);
  for I := 0 to Pred(W_Len) do begin
    // use W[I] as needed ...
  end;

  W := @ARRAY_D[1];
  W_Len := Length(ARRAY_D);
  for I := 0 to Pred(W_Len) do begin
    // use W[I] as needed ...
  end;
end;

推荐阅读