迭代记录字段

时间:2016-03-03 13:35:57

标签: delphi for-loop records

如何使用for循环遍历G1-G4的记录字段?

  TrFireGroup = record   
    idx: integer; 
    G1: integer;
    G2: integer;
    G3: integer;
    G4: integer;
    FGroup: integer;
    MstIdx: integer; 
    Status: byte;
    procedure Clear;
  end;

4 个答案:

答案 0 :(得分:3)

这可能不是一个好主意,但它是可能的。

procedure Test();
var
  i: Integer;
  rec: TrFireGroup;
  GPtr: PInteger;
  value: Integer;
begin
  // Initialize rec ...

  // Get pointer to first G? field
  GPtr := @rec.G1;

  // Loop over G fields
  for i := 0 to 3 do
  begin
    // Use value G? field here...
    // For example: value := GPtr^;

    // Increment pointer, thus moving it with four bytes.
    Inc(GPtr);
  end;
end;
  • 首先获取指针(GPtr)到rec中的第一个字段。

  • 然后,我们通过取消引用指针(GPtr^)来使用该值。

  • 最后,将指针递增到下一个值(Inc(GPtr))。 请注意,增量是将指针移动到所引用类型的大小。

    当我们使用指向Integer(PInteger)的指针时,Inc将指针移动到SizeOf(Integer),前进到记录中的下一个字段。

    < / LI>

同样,这不是一个好习惯。

在这种情况下,指针算法是过度的,除非你在记录中有数百个字段(这是非常罕见的),但如果你真的需要,这是一种方法。

仅供参考,这里有关于Delphi和指针算法指针的非常详细和高质量的解释:

  

答案 1 :(得分:3)

如果您需要维护现有的记录接口结构以实现兼容性,则可以使用属性来执行此操作。将值存储在数组中允许您枚举它们,并且可以使用现有名称定义属性以直接以现有方式访问值。

program Project1;    
{$APPTYPE CONSOLE}   

type
  TGArray = array[0..3] of integer;
  TrFireGroup = record
    private
      FGArr : TGArray;
    public
      idx: integer;
      FGroup: integer;
      MstIdx: integer;
      Status: byte;         
      property G1 : integer read FGArr[0] write FGArr[0];
      property G2 : integer read FGArr[1] write FGArr[1];
      property G3 : integer read FGArr[2] write FGArr[2];
      property G4 : integer read FGArr[3] write FGArr[3];
      property GArray : TGArray read FGArr;
  end;

var
  LFireGroup : TrFireGroup;
  j : integer;
begin
  LFireGroup.G1 := 1;
  LFireGroup.G2 := 3;
  LFireGroup.G3 := 5;
  LFireGroup.G4 := 7;

  for j in LFireGroup.GArray do
    WriteLn(j);    
  ReadLn;
end.

如果您需要将记录布局与二进制兼容(无论出于何种原因),您可以放弃一些整洁和重新排列的东西

  TrFireGroup = record        
    idx: integer;
    GArray : TGArray;
    FGroup: integer;
    MstIdx: integer;
    Status: byte;
    procedure Clear;         
    property G1 : integer read GArray[0] write GArray[0];
    property G2 : integer read GArray[1] write GArray[1];
    property G3 : integer read GArray[2] write GArray[2];
    property G4 : integer read GArray[3] write GArray[3];          
  end;

GArray作为公共字段也允许您进行索引编写(而这不可能作为普通属性) - 即:

for i := Low(TGArray) to High(TGArray) do
    LFireGroup.GArray[i] := 2*i;

或者,如果您可以放弃for/in语义,则可以将数组定义为默认属性并直接引用该记录:

  TrFireGroup = record
    private
      FGArr : TGArray;
      procedure SetG(index:integer; Value:integer);
      function GetG(index:integer) : integer;
    public
      property G1 : integer read FGArr[0] write FGArr[0];
      property G2 : integer read FGArr[1] write FGArr[1];
      property G3 : integer read FGArr[2] write FGArr[2];
      property G4 : integer read FGArr[3] write FGArr[3];
      property GArray[index:integer]:integer read GetG write SetG; default;
  end;

procedure TrFireGroup.SetG(index:integer; Value:integer);
begin
  FGArr[index] := Value;
end;

function TrFireGroup.GetG(index: Integer) : integer;
begin
  result := FGArr[index];
end;

允许你这样做:

for i := Low(TGArray) to High(TGArray) do
  LFireGroup[i] := 2*i;

for i := Low(TGArray) to High(TGArray) do
  WriteLn(LFireGroup[i]);

答案 2 :(得分:1)

如果您使用的是最近的Delphi版本并且只需要G1..G4的当前值(即不写入它们),您也可以使用此方法:

var
  I: Integer;
  fg: TrFireGroup;
  arr: TArray<Integer>;
begin
  ...
  arr := [fg.G1, fg.G2, fg.G3, fg.G4];
  for I in arr do begin
    Writeln(I);
  end;
  ...
end;

答案 3 :(得分:1)

恕我直言,如果您不需要二进制兼容性,那么最简单的选择就是使用variant record

TrFireGroup = record
  idx: integer;
  FGroup: integer;
  MstIdx: integer;
  Status: byte;
  procedure Clear;
  case Integer of
    0: (G1: integer; G2: integer; G3: integer; G4: integer);
    1: (GArr: array[0..3] of integer);
end;

这相当于旧的Delphi absolute关键字。阵列和四个G?变量在内存中占有相同的位置。