【问题标题】:Pass record parameter without declaring it first as a variable传递记录参数而不首先将其声明为变量
【发布时间】:2012-02-10 16:34:52
【问题描述】:

如果我试图调用具有记录类型(不是对象)作为参数的过程,是否可以以某种方式“内联”传递该参数的详细信息而无需先声明该类型的变量?

例如假设我有这个简单的记录类型:

type TMyRecord = record
  AString: string;
  AnInt: Integer;
end;

还有这个过程声明:

procedure MyProcedure(Rec: TMyRecord);

如果我想调用 MyProcedure,我必须声明一个 TMyRecord 类型的变量还是可以执行以下操作:

MyProcedure(TMyRecord("Test", 10));

这不起作用(XE2)(得到一个关于它的编译器错误,需要一个“)”)。

那么,我可以这样做吗?或者不可能。

谢谢

【问题讨论】:

  • 下面正在进行一场战争。我认为理想的答案是“没有语法可以创建任意记录实例'内联',但是对于任何给定的记录,您可以通过 [Brian 的回答如下: ]"

标签: delphi delphi-xe2


【解决方案1】:

只是玩弄约翰·伊斯利的想法:

type TRec = record
  X: string;
  Y: Integer;
end;

procedure TestRec(const Rec: array of const);
var
  R: TRec;

begin
  R.X:= string(Rec[0].VUnicodeString);
  R.Y:= Rec[1].VInteger;
  ShowMessage(R.X + IntToStr(R.Y));
end;

procedure TForm1.Button7Click(Sender: TObject);
begin
  TestRec(['Test', 22]);
end;

可以将记录字段作为array of const 参数传递,并将这些参数分配给本地记录变量。

【讨论】:

  • -1。这是不必要的复杂。用两个参数声明函数,每个字段一个。给他们特定的类型。从调用站点中删除括号。
  • @RobKennedy - 你的提议很枯燥。编程应该很有趣。 :)
【解决方案2】:

可以使用advanced record 结构。

有关advanced records 的更多信息,请参阅Delphi 帮助中的Records (advanced) section

这是一个小型原型,用于查看在您的情况下如何在函数/过程调用中预初始化记录:

Type
  TRecord = record
   AString : String;
   AnInt : Integer;
   Constructor Create( Const s : String; i : Integer);
  end;

constructor TRecord.Create(const s: String; i: Integer);
begin
  AString := s;
  AnInt := i;
end;

procedure DoSomething( theRec : TRecord);
begin
  WriteLn(theRec.AString, ' ',theRec.AnInt);
end;

begin
  DoSomeThing( TRecord.Create('S',1));
  ReadLn;
end.

查看 Delphi RTL,请参阅单元 system.types (XE2) 中记录类型 TPointTRect 的定义。 他们定义了一些重载的Create 构造函数,它们在很多地方用于在函数/过程调用中预初始化记录结构。

【讨论】:

  • @KenWhite:一个函数,这样你就可以避免在你只想传递几个值的任何地方声明一个 var,对我来说似乎不是“大量代码”。该类型在别处声明是没有意义的(只要它不在库中)。
  • 我不打算参与这里正在进行的“战争”,但就这种方法和Brian的方法的区别而言,我仍然不确定我更喜欢哪一种……跨度>
  • 由于历史原因,提供变通解决方案是有益的。
  • @Andreas - 并不是说​​它应该是偏好的原因,但一个区别是可以内联独立函数。
  • @Sertac,编译器也没有内联构造函数版本的技术原因。我想这两个版本编译成非常相似的机器代码。如果 Delphi 不内联构造函数调用,这似乎是当前编译器的限制,而不是记录构造函数的固有限制。
【解决方案3】:

会很好!但是,没有。

如果内联传递确实是您的目标,那么也许开放数组参数会适合您。

Procedure MyProcedure(const Vars: Array of Variant);
begin
  ShowMessage(VarToStr(Vars[0])+'  '+VarToStr(Vars[1]));
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
   MyProcedure(['Test', 12]);
end;

您还可以传递一个常量数组,它基本上是一个 TVarRec 数组,它是一个变体记录,其中还包括类型信息作为 VType。这是有趣的东西..

可以在 Rudy 的 Delphi Corner 上找到一篇出色的文章: Rudy's Delphi Corner, Open Array Parameters

【讨论】:

  • -1。我认为没有理由这样做。如果您不打算传递整个记录,最好简单地声明两个不同的类型参数。然后编译器可以告诉你是否拥有一切,而不是函数必须在运行时检查它。
  • 哇,-1 提供了一种在不创建本地变量的情况下传递记录的方法?我看不出我的回答如何不适用于这个问题。我看不到赞成票,但反对票?再次,哇。
  • 如果它没有应用于这个问题,我会标记它。您的答案适用于该问题,但这是一个糟糕的答案,因为它需要的任务很容易被强类型化并使其弱类型化并且在语法上很奇怪。
【解决方案4】:

您提出的问题与代码可读性有关,并且有一种解决方案可以避免创建变量。 VCL 将此解决方案与TPointTRect 记录一起使用。

考虑TPoint的定义:

type
  TPoint = record
    X,Y integer
  end;

要将TPoint 传递给您可能执行的过程:

var
  MyPoint : TPoint;

begin
  MyPoint.X := 5;
  MyPoint.Y := 7;
  DoSomething( MyPoint );
end;

这很好,但是当使用工厂函数Point 也可以使用时需要 3 行:

begin
  DoSomething( Point(5,7) );
end;

在 Delphi 中,函数声明如下:

function Point( X, Y : integer ) : TPoint;
begin
  Result.X := X;
  Result.Y := Y;
end;

然后你可以调用这个函数'inline'来快速创建记录'on the fly' 你会看到为TRect等提供了相同的功能。我经常将这样的工厂函数与记录声明放在一起如下,即使我不打算使用它们:

type
  TMyRecord = record
    A : integer;
    B : string;
  end;

function MyRecord( A : integer; const B : string ) : TMyRecord;
begin
  Result.A := A;
  Result.B := B;
end;

使用这种技术可以提高代码的可读性,还可以确保您不会意外忽略设置记录元素。

【讨论】:

  • 我认为它确实回答了这个问题(“那么,我可以做这样的事情吗?” - Brian Frost 提供了一种方法来做这样的事情:))跨度>
  • @KenWhite:一个函数MyRect,这样你就可以避免在任何地方声明一个var,你只想传递几个值,对我来说似乎不是“大量代码”。在此解决方案中,在其他地方声明类型完全没有意义。
  • @KenWhite:如果我们只回答了所提出的确切问题,那么 SO 的帮助将大大降低。也许 Brian 和 LU RD 都应该在他们的回答前加上“不,这是不可能的,但这是一个解决方法”,但在我看来,他们的回答暗示了他们用简短的是/否以外的东西来回答。跨度>
  • @KenWhite 是的。不用担心 :-) 如果 Brian 和 LU RD 给出的答案不是 Delphi 特定的,我会同意你的。但它们是特定于德尔福的。在我看来,阅读问题的意图和字面意思很重要。
  • @KenWhite:如果你查看 VCL 源代码(和其他完善的库),你会看到到处都是 Point(X,Y) 工厂解决方案,原因是如果你去首先声明记录的麻烦,它可能对您来说是一个非常重要的结构,具有很大的范围 - 因此,如果您打算内联初始化它,则值得添加一个工厂函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
相关资源
最近更新 更多