0

我有 10 个双变量,我想用值 0 进行初始化。它们是非结构化的,不是设计的数组的一部分。

procedure Initialize;
var
  a1, a2, a3, a4, a5, b1, b2, b3, b4, b5: Double;
begin
  a1 := 0; 
  a2 := 0;
  a3 := 0;
  a4 := 0;
  a5 := 0;

  b1 := 0; 
  b2 := 0;
  b3 := 0;
  b4 := 0;
  b5 := 0;
end;

为了重构那段代码,我引入了一个辅助方法AssignValue。

procedure Initialize;
var
  a1, a2, a3, a4, a5, b1, b2, b3, b4, b5: Double;
begin
  AssignValue(0,a1); 
  AssignValue(0,a2);
  ...
end;

procedure AssignValue(value: Double; var target: Double);
begin
  target:= value;
end;

如何编写一个更通用的AssignValue过程,它接受任意数量的参数并使调用成为AssignValue(0,a1,a2,a3,a4,a5,b1,b2,b3,b4,b5)可能?

额外的问题:假设作为第一个参数,您如何编写该程序以使其以任何顺序考虑doubleint引用。value: Int

4

3 回答 3

7

你可以这样做:

procedure AssignValue(const Value: Double; const Addresses: array of PDouble);
var
  i: Integer;
begin
  for i := low(Addresses) to high(Addresses) do
    Addresses[i]^ := Value;
end;

像这样称呼它:

AssignValue(0.0, [@a1, @a2, @a3, ...]);

在这里,我们传递了一个包含变量地址的开放数组。

要支持多种类型,您将使用如下声明的重载:

procedure AssignValue(const Value: Double; const Addresses: array of PDouble); 
  overload;
procedure AssignValue(const Value: Integer; const Addresses: array of PInteger); 
  overload;
// and so on, implementation of these functions is obvious

由您来判断这是否比您当前的解决方案更好。就个人而言,我会坚持使用普通的旧赋值运算符。另一种选择是将变量放在记录中并分配Default(TMyRecord)给您的记录变量。

于 2013-10-15T08:36:53.213 回答
2

您可以为此使用开放数组参数:

procedure AssignValue(value: double; const arr: array of PDouble);
var
  i: Integer;
begin
  for i := 0 to length(arr)-1 do
    PDouble(arr[i])^ := value;
end;

像这样使用它(对于此类任务,我看不到避免使用“@”的方法):

AssignValue(1, [@a1,@a2,@a3]);
于 2013-10-15T08:36:40.807 回答
0

首先,您可以使用记录和调用,但如果您有一些内部引用计数值(如)fillchar(myrecord,sizeof(myrecord),0),则可能容易出错。string

但是在您的情况下,由于它只是double值,因此可能很容易编写:

procedure Initialize;
var localdata: record
    a1, a2, a3, a4, a5, b1, b2, b3, b4, b5: Double;
    obj: TObject;
    i1, i2, i3, i4: integer;
  end;
begin
  fillchar(localdata,sizeof(localdata),0);
  with localdata do
  begin
    a1 := 10;
    a2 := a1+10; 
    assert(obj=nil);
    inc(i1,20);
    i2 := i1+10;
    assert(i2=30);
  end;
end;

如您所见,您甚至可以在记录中混合类型。诀窍是你定义你的记录类型内联,没有任何类型定义,这是不需要的。

我承认这不是直接的答案,但我谦虚地建议您更改设计以切换到更“与 OOP 兼容”的东西。

只需使用动态数组或类来嵌入值。默认情况下,它们都将设置为 0。

对于动态数组:

var a,b: array of double;

SetLength(a,5); // then use a[0] instead of a1, a[2] instead of a2...
SetLength(b,5); // then use b[0] instead of b1, b[2] instead of b2...

对于一个类 - 这是我的首选,因为您可以将代码作为好的对象嵌入到数据中:

type
  TMyClass = class
  public
    a1, a2, a3, a4, a5, b1, b2, b3, b4, b5: Double;
    procedure OneMethodHere;
    function OneTestHere(aValue: double): boolean;
  end;

var C: TMyClass;

  C := TMyClass.Create; // every C member will be set to 0
  try
    if C.OneTestHere(10) then
      C.OneMethodHere;
    // you can use C.a1 or C.b5
  finally
    C.Free;
  end;
于 2013-10-15T18:48:11.583 回答