You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将不同Record类型存入临时变量并在函数间传递?

如何将不同Record类型存入临时变量并在函数间传递?

兄弟,我明白你想实现的需求——用一个通用变量存不同的record类型,不用每次都声明特定类型,还能在需要的时候转回原类型处理。在Delphi里,因为record是值类型,直接用Variant确实不太好搞,不过有几个靠谱的方案能满足你的需求,而且完全适配你“自己把控类型、不需要安全检查”的要求,我给你详细说说:

方案一:用NativeUInt+指针(轻量化,适合不依赖RTTI的场景)

既然你不需要安全检查,直接用指针存储record的地址,再转成NativeUInt作为通用临时变量是最直接的方式。不过要注意record的生命周期,别让局部变量的内存被回收后再使用就行。

先看修改后的完整代码:

type
  TMyRec1 = packed record
    SomeValue: Integer;
  end;

  TMyRec2 = packed record
    ThisIsMessage: string;
  end;

function GetRec(recId: Integer): NativeUInt;
var
  Rec1: TMyRec1;
  Rec2: TMyRec2;
begin
  case recId of
    1:
      begin
        Rec1.SomeValue := 123; // 初始化示例值
        // 注意:如果用局部变量,函数退出后内存会被回收!实际项目建议用动态分配
        // 动态分配修正版:
        // Result := NativeUInt(GetMem(SizeOf(TMyRec1)));
        // TMyRec1(Result^).SomeValue := 123;
        Result := NativeUInt(@Rec1);
      end;
    2:
      begin
        Rec2.ThisIsMessage := 'Hello World';
        // 动态分配修正版:
        // Result := NativeUInt(GetMem(SizeOf(TMyRec2)));
        // TMyRec2(Result^).ThisIsMessage := 'Hello World';
        Result := NativeUInt(@Rec2);
      end;
  end;
end;

function GetRec1(rec: NativeUInt): TMyRec1;
begin
  // 直接将指针转回原record类型
  Result := TMyRec1(PByte(rec)^);
  // 如果是动态分配的record,用完记得调用FreeMem(PByte(rec)); 释放内存
end;

function GetRec2(rec: NativeUInt): TMyRec2;
begin
  Result := TMyRec2(PByte(rec)^);
end;

procedure PrintRec1(rec: TMyRec1);
begin
  Writeln(IntToStr(rec.SomeValue));
end;

procedure PrintRec2(rec: TMyRec2);
begin
  Writeln(rec.ThisIsMessage);
end;

procedure MainFunction;
var
  myRec: NativeUInt;
begin
  myRec := GetRec(1);
  PrintRec1(GetRec1(myRec));
  
  myRec := GetRec(2);
  PrintRec2(GetRec2(myRec));
end;

方案二:用TValue(Delphi XE7+,更优雅,无需手动管理内存)

如果你的Delphi版本是XE7及以上,System.Rtti单元里的TValue是专门用来存储各种类型值的工具,包括record类型,转换起来非常方便,还不用手动处理内存分配和释放。

代码示例:

uses
  System.Rtti;

type
  TMyRec1 = packed record
    SomeValue: Integer;
  end;

  TMyRec2 = packed record
    ThisIsMessage: string;
  end;

function GetRec(recId: Integer): TValue;
var
  Rec1: TMyRec1;
  Rec2: TMyRec2;
begin
  case recId of
    1:
      begin
        Rec1.SomeValue := 456;
        Result := TValue.From<TMyRec1>(Rec1);
      end;
    2:
      begin
        Rec2.ThisIsMessage := 'Hi there';
        Result := TValue.From<TMyRec2>(Rec2);
      end;
  end;
end;

function GetRec1(rec: TValue): TMyRec1;
begin
  // 直接转换,你自己保证类型正确,无需额外检查
  Result := rec.AsType<TMyRec1>;
end;

function GetRec2(rec: TValue): TMyRec2;
begin
  Result := rec.AsType<TMyRec2>;
end;

procedure PrintRec1(rec: TMyRec1);
begin
  Writeln(IntToStr(rec.SomeValue));
end;

procedure PrintRec2(rec: TMyRec2);
begin
  Writeln(rec.ThisIsMessage);
end;

procedure MainFunction;
var
  myRec: TValue;
begin
  myRec := GetRec(1);
  PrintRec1(GetRec1(myRec));
  
  myRec := GetRec(2);
  PrintRec2(GetRec2(myRec));
end;

关于你提到的“继承式record”的说明

你后来写的TMyRec1 = TMyRec这种写法在Delphi里是语法错误的,因为Delphi的record不支持继承。如果想让多个record有“共同基类”的感觉,可以把公共字段放到单独的record里嵌套使用,或者用变体record:

type
  TMyBaseRec = record
    RecType: Integer; // 标记当前是哪种record类型,方便自己判断
  end;

  TMyRec1 = record
    Base: TMyBaseRec;
    SomeValue: Integer;
  end;

  TMyRec2 = record
    Base: TMyBaseRec;
    ThisIsMessage: string;
  end;

不过这种方式本质还是不同的record类型,适配你的需求的话,前面两种方案会更直接。

备注:内容来源于stack exchange,提问作者Secretary Of Education

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 15:27:48