我想创建一个对变量记录类型执行一些操作的过程。在全球范围内,我有一系列记录。我想对数组进行排序,但要按记录的字段进行排序。我想将该字段作为参数传递给过程。问题是:
如何将记录的字段作为参数传递?例如:函数
f2
应返回字段的值和字段的偏移量。
type TCell = record
a: byte;
b: byte;
end;
function f2(cell: Tcell; offset: byte): byte;
begin
{ ** } result:=cell.offset { ** }
end;
begin
c: TCell;
c.a:=10; c.b:=20;
writeln(f2(c, 2)) // 20;
end;
在Delphi中可以吗?在 FreePascal 中通过指针当然是可能的,但以下内容在 Delphi 中不起作用,并且编译器会引发错误:
E2015“运算符不适用于此操作数类型”
function f1(a: pointer; offset: integer): byte;
begin
f1 := PByte(a+offset)^; // ← error here
end;
begin
cell.a:=10; cell.b:=20;
writeln(f1(@cell,0));
writeln(f1(@cell,1));
end.
好吧,让我先回答你的“实际”问题:
在全球范围内,我有一系列记录。我想对数组进行排序,但是按记录的字段排序。
在现代版本的 Delphi 中,您可以使用泛型来实现此目的:
type
TCell = record
a, b: Byte
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
var Arr := TArray<TCell>(nil);
TArray.Sort<TCell>(
Arr,
TComparer<TCell>.Construct(
function(const Left, Right: TCell): Integer
begin
Result := Left.a - Right.a // no overflow risk
end
)
);
end;
我想将该字段作为过程的参数传递。
为各个字段创建枚举类型并使用
case
语句。
您也可以使用 RTTI,但性能不会那么好。
在 Pascal 中通过指针当然是可能的
您也可以在 Delphi 中使用指针,但这很少是好的做法,除非您是 Delphi 专家并且确实需要绝对最佳的性能或最出色的代码。
type
TCell = packed record
a, b: Byte
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
var Cell := Default(TCell);
Cell.a := 100;
Cell.b := 200;
var p := PByte(@Cell);
ShowMessage(p^.ToString);
ShowMessage((p + 1)^.ToString);
end;
这里的技巧是
PByte
是在指针算术开启的情况下声明的。事实上,在System.pas
你会发现
{$POINTERMATH ON}
PByte = ^Byte; {$NODEFINE PByte} { defined in sysmac.h }
{$POINTERMATH OFF}
您始终可以在自己的指针类型上使用此技巧。
您的代码
f1 := PByte(a+offset)^; //<--- error here
不起作用,因为
a
是 Pointer
和 offset
是 Integer
,而你不能 +
是 Pointer
和 Integer
。
但是
PByte(PByte(a) + offset)^
会起作用。