4

我将维护并移植到 Delphi XE2 一堆非常旧的 Delphi 代码,这些代码充满了VarArrayCreate构造,以伪造具有不为零的下限的动态数组。

使用Variant类型的缺点是:

  • 比原生数组慢很多(代码做了很多复杂的财务计算,所以速度很重要)
  • 类型不安全(尤其是意外使用了错误的var...常量,并且 Variant 系统开始进行不需要的转换或舍入时)

如果我可以使用动态数组,两者都可能变得没有意义。

变体数组的好处是它们可以有非零的下限。

我记得动态数组过去总是从零的下限开始。

这仍然是真的吗?换句话说:是否可以让动态数组从不同于零的边界开始

作为一个特定案例的前后示例的说明(单维,但代码中充满了多维数组,除了varDouble之外,代码还使用了TVarData允许使用的各种其他varXXX数据类型):

function CalculateVector(aSV: TStrings): Variant;
var
  I: Integer;
begin
  Result := VarArrayCreate([1,aSV.Count-1],varDouble);
  for I := 1 to aSV.Count-1 do
    Result[I] := CalculateItem(aSV, I);
end;

CalculateItem函数Double返回。界限是从1aSV.Count-1

当前的替换是这样的,用 Result 的空间零元素来改进编译时间检查:

type
  TVector = array of Double;
function CalculateVector(aSV: TStrings): TVector;
var
  I: Integer;
begin
  SetLength(Result, aSV.Count); // lower bound is zero, we start at 1 so we ignore the zeroth element
  for I := 1 to aSV.Count-1 do
    Result[I] := CalculateItem(aSV, I);
end;
4

2 回答 2

5

动态数组的下限总是0. 因此,对于所有动态数组都low(A)等于。0这甚至适用于空动态数组,即nil.

文档中:

动态数组总是整数索引,总是从 0 开始。

于 2012-12-20T14:14:06.523 回答
2

已经回答了您的直接问题,我还为您提供了一个通用类的开始,您可以在移植中使用它。

type
  TSpecifiedBoundsArray<T> = class
  private
    FValues: TArray<T>;
    FLow: Integer;
    function GetHigh: Integer;
    procedure SetHigh(Value: Integer);
    function GetLength: Integer;
    procedure SetLength(Value: Integer);
    function GetItem(Index: Integer): T;
    procedure SetItem(Index: Integer; const Value: T);
  public
    property Low: Integer read FLow write FLow;
    property High: Integer read GetHigh write SetHigh;
    property Length: Integer read GetLength write SetLength;
    property Items[Index: Integer]: T read GetItem write SetItem; default;
  end;

{ TSpecifiedBoundsArray<T> }

function TSpecifiedBoundsArray<T>.GetHigh: Integer;
begin
  Result := FLow+System.High(FValues);
end;

procedure TSpecifiedBoundsArray<T>.SetHigh(Value: Integer);
begin
  SetLength(FValues, 1+Value-FLow);
end;

function TSpecifiedBoundsArray<T>.GetLength: Integer;
begin
  Result := System.Length(FValues);
end;

procedure TSpecifiedBoundsArray<T>.SetLength(Value: Integer);
begin
  System.SetLength(FValues, Value);
end;

function TSpecifiedBoundsArray<T>.GetItem(Index: Integer): T;
begin
  Result := FValues[Index-FLow];
end;

function TSpecifiedBoundsArray<T>.SetItem(Index: Integer; const Value: T);
begin
  FValues[Index-FLow] := Value;
end;

我认为这是很明显的。我考虑使用 arecord但我认为这是行不通的。这取决于值类型语义FLow和引用类型语义的混合FValues。所以,我认为在这里上课是最好的。

当您修改Low.

毫无疑问,你想扩展它。你会添加一个SetBounds,一个副本,一个副本等等。但我认为您可能会发现它很有用。它当然展示了如何制作一个看起来非常像具有非零下限的数组的对象。

于 2012-12-20T21:59:15.000 回答