Delphi SetLength 自定义索引

6
在Delphi中,可以创建一个指定类型的数组。
var
  Arr: array[2..N] of MyType;

这是一个由2到N标记的包含N - 1个元素的数组。

如果我们改为声明一个动态数组

var
  Arr: array of MyType

然后通过以下方式分配N - 1个元素

SetLength(Arr, N - 1)

那么元素将从0到N-2进行索引。是否可以使它们从2到N(例如)进行索引?

4个回答

15

不,Delphi 中的动态数组始终从零开始索引。


1

是的! 通过使用一个技巧!
首先声明一个新类型。我使用记录类型而不是类,因为记录更容易使用。

type
  TMyArray = record
  strict private
    FArray: array of Integer;
    FMin, FMax:Integer;
    function GetItem(Index: Integer): Integer;
    procedure SetItem(Index: Integer; const Value: Integer);
  public
    constructor Create(Min, Max: integer);
    property Item[Index: Integer]: Integer read GetItem write SetItem; Default;
    property Min: Integer read FMin;
    property Max: Integer read FMax;
  end;

有了记录类型的定义,现在您需要实现一些代码:

constructor TMyArray.Create(Min, Max: integer);
begin
  FMin := Min;
  FMax := Max;
  SetLength(FArray, Max + 1 - Min);
end;

function TMyArray.GetItem(Index: Integer): Integer;
begin
  Result := FArray[Index - FMin];
end;

procedure TMyArray.SetItem(Index: Integer; const Value: Integer);
begin
  FArray[Index - FMin] := Value;
end;

现在,您已经声明了类型,可以开始使用它了:
var
  Arr: TMyArray;
begin
  Arr := TMyArray.Create(2, 10);
  Arr[2] := 10;

实际上,创建具有特定范围的数组是一个简单的技巧,如果您喜欢,可以使其更加灵活。或者将其转换为类。就我个人而言,我更喜欢使用记录来表示这些简单类型。


0

唯一能模仿这种行为的方法是使用指针。

type
  TMyTypeArr = array [ 0..High(Integer) div sizeof( MyType ) - 1 ] of Mytype;
  PMyTypeArr = ^TMyTypeArr;
var
  x: ;
  A: PMyTypeArr;
begin
  SetLength( A, 2 );
  x := PMyTypeArr( @A[ 0 ] ); Dec( PMyType( x ), 2 ); // now [2,4> is valid.
  x[2] := Get_A_MyType();
end;  

请注意,您会失去任何范围检查,并将其与非零起始数组结合使用是一个非常非常糟糕的想法!

0
如果你真的需要这个索引,那么你可以编写一个简单的“翻译”函数,该函数将接收范围在2到N之间的索引数字,并通过减去参数来返回从0到N-2的索引,例如:
function translate(i : integer) : integer;
begin
  result := i - 2;
end;

你可以这样调用你的数组:

array[translate(2)]

当然,你可以在函数内部进行范围检查,也许你可以给它一个更短的名字。
或者更好的方法是,使用这样一个函数来包装整个数组的访问:
function XYZ(i : integer) : MyType;
begin
  // Do range checking here...
  result := MyArray[i - 2];
end;

希望这可以帮到你。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接