Delphi中2D数组的索引运算符属性



我知道在Delphi中,当你想允许使用索引运算符[]时,你必须做一些事情,比如

property Item[index: integer]: integer read GetData; default;

如何在Delphi中实现多维数组,从而允许使用以下内容:

matrix := TMatrix<integer>.Create(3,3);
matrix[0][2] := 5;
WriteLn(matrix[0][2]);

不能那样使用[][]。但是您可以在一个属性中声明多个索引,例如:

type
TMatrix<T> = class
private
function GetData(index1, index2: Integer): T;
procedure SetData(index1, index2: Integer; value: T);
public
constructor Create(dim1, dim2: Integer);
property Item[index1, index2: Integer]: T read GetData write SetData; default;
end;

然后你可以这样做:

matrix := TMatrix<integer>.Create(3,3);
matrix[0, 2] := 5;
WriteLn(matrix[0, 2]);

如果愿意,可以使用[][]访问元素。如果您的类型是数组(二维或锯齿状动态),那么这种访问元素的方法就会被烘焙到语言中。对于用户定义的类型,则需要实现它

在用户定义的类型中,没有办法在单个步骤中实现[][]。你需要做的是把这个过程分成两个独立的部分。第一部分是实现[]以返回矩阵的一行。然后在该行上实现[]以返回一个元素。这里有一个例子:

type
TMatrix<T> = class
public
type
TRow = record
private
FMatrix: TMatrix<T>;
FRowIndex: Integer;
function GetItem(ColIndex: Integer): T; inline;
procedure SetItem(ColIndex: Integer; const Value: T); inline;
public
property Items[ColIndex: Integer]: T read GetItem write SetItem; default;
end;
private
FData: TArray<TArray<T>>;
function GetRow(RowIndex: Integer): TRow; inline;
public
constructor Create(RowCount, ColCount: Integer);
property Rows[RowIndex: Integer]: TRow read GetRow; default;
end;
{ TMatrix<T>.TRow }
function TMatrix<T>.TRow.GetItem(ColIndex: Integer): T;
begin
Result := FMatrix.FData[FRowIndex, ColIndex];
end;
procedure TMatrix<T>.TRow.SetItem(ColIndex: Integer; const Value: T);
begin
FMatrix.FData[FRowIndex, ColIndex] := Value;
end;
{ TMatrix<T> }
constructor TMatrix<T>.Create(RowCount, ColCount: Integer);
begin
inherited Create;
SetLength(FData, RowCount, ColCount);
end;
function TMatrix<T>.GetRow(RowIndex: Integer): TRow;
begin
Result.FMatrix := Self;
Result.FRowIndex := RowIndex;
end;

然而,在说明了这是可能的之后,我建议使用带有两个索引的数组属性更为惯用。这意味着您将使用M[Row,Col]而不是M[Row][Col]访问矩阵。这个特殊的习语(M[Row,Col])并不是在所有语言中都能找到,所以你可能不熟悉它

type
TMatrix<T> = class
public
type
TRow = record
private
FMatrix: TMatrix<T>;
FRowIndex: Integer;
function GetItem(ColIndex: Integer): T; inline;
procedure SetItem(ColIndex: Integer; const Value: T); inline;
public
property Items[ColIndex: Integer]: T read GetItem write SetItem; default;
end;
private
FData: TArray<TArray<T>>;
function GetRow(RowIndex: Integer): TRow; inline;
function GetItem(RowIndex, ColIndex: Integer): T; inline;
procedure SetItem(RowIndex, ColIndex: Integer; const Value: T); inline;
public
constructor Create(RowCount, ColCount: Integer);
property Rows[RowIndex: Integer]: TRow read GetRow;
property Items[RowIndex, ColIndex: Integer]: T read GetItem write SetItem; default;
end;
{ TMatrix<T>.TRow }
function TMatrix<T>.TRow.GetItem(ColIndex: Integer): T;
begin
Result := FMatrix.FData[FRowIndex, ColIndex];
end;
procedure TMatrix<T>.TRow.SetItem(ColIndex: Integer; const Value: T);
begin
FMatrix.FData[FRowIndex, ColIndex] := Value;
end;
{ TMatrix<T> }
constructor TMatrix<T>.Create(RowCount, ColCount: Integer);
begin
inherited Create;
SetLength(FData, RowCount, ColCount);
end;
function TMatrix<T>.GetRow(RowIndex: Integer): TRow;
begin
Result.FMatrix := Self;
Result.FRowIndex := RowIndex;
end;
function TMatrix<T>.GetItem(RowIndex, ColIndex: Integer): T;
begin
Result := FData[RowIndex, ColIndex];
end;
procedure TMatrix<T>.SetItem(RowIndex, ColIndex: Integer; const Value: T);
begin
FData[RowIndex, ColIndex] := Value;
end;

请注意,在此版本中,我们已选择将Items作为默认属性。这意味着,如果要访问一行,则必须显式命名Rows属性:M.Rows[RowIndex]

最新更新