遍历记录字段
Iterate over record fields
如何用for循环遍历G1-G4的记录字段?
TrFireGroup = record
idx: integer;
G1: integer;
G2: integer;
G3: integer;
G4: integer;
FGroup: integer;
MstIdx: integer;
Status: byte;
procedure Clear;
end;
这可能不是一个好主意,但它是可能的。
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;
首先得到一个指向rec.
中第一个字段的指针(GPtr
)
然后,我们通过取消引用指针(GPtr^
)来使用该值。
最后,将指针递增到下一个值 (Inc(GPtr)
)。
请注意,增量是将指针移动到被引用类型的大小。
并且由于我们正在使用指向整数 (PInteger
) 的指针,Inc
将指针移动到 SizeOf(Integer)
,从而前进到记录中的下一个字段。
同样,这不是好的做法。
在这种情况下,指针运算有点矫枉过正,除非记录中有数百个字段(这种情况非常罕见),但如果确实需要,这是一种实现方法。
仅供参考,Delphi中的指针和指针运算在这里有非常详细和高质量的解释:
如果您需要维护现有的记录接口结构以实现兼容性,您可以使用属性来执行此操作。将值存储在数组中允许您枚举它们,并且您可以使用现有名称定义属性以直接以现有方式访问值。
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
保留为 public 字段还可以让您进行索引写入(而将其作为普通 属性 是不可能的)- 即:
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]);
如果您使用的是最新的 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;
恕我直言,如果您不需要二进制兼容性,那么最简单的选择是使用 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
关键字。既是数组又是4个G?变量在内存中共享相同的位置。
如何用for循环遍历G1-G4的记录字段?
TrFireGroup = record
idx: integer;
G1: integer;
G2: integer;
G3: integer;
G4: integer;
FGroup: integer;
MstIdx: integer;
Status: byte;
procedure Clear;
end;
这可能不是一个好主意,但它是可能的。
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;
首先得到一个指向rec.
中第一个字段的指针(然后,我们通过取消引用指针(
GPtr^
)来使用该值。最后,将指针递增到下一个值 (
Inc(GPtr)
)。 请注意,增量是将指针移动到被引用类型的大小。并且由于我们正在使用指向整数 (
PInteger
) 的指针,Inc
将指针移动到SizeOf(Integer)
,从而前进到记录中的下一个字段。
GPtr
)
同样,这不是好的做法。
在这种情况下,指针运算有点矫枉过正,除非记录中有数百个字段(这种情况非常罕见),但如果确实需要,这是一种实现方法。
仅供参考,Delphi中的指针和指针运算在这里有非常详细和高质量的解释:
如果您需要维护现有的记录接口结构以实现兼容性,您可以使用属性来执行此操作。将值存储在数组中允许您枚举它们,并且您可以使用现有名称定义属性以直接以现有方式访问值。
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
保留为 public 字段还可以让您进行索引写入(而将其作为普通 属性 是不可能的)- 即:
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]);
如果您使用的是最新的 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;
恕我直言,如果您不需要二进制兼容性,那么最简单的选择是使用 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
关键字。既是数组又是4个G?变量在内存中共享相同的位置。