Kha*_*lid 5 arrays delphi generics record tlist
我有一个通用的记录列表。这些记录包含一个动态数组,如下所示
Type
TMyRec=record
MyArr:Array of Integer;
Name: string;
Completed: Boolean;
end;
var
MyList:TList<TMyRec>;
MyRec:TMyRec;
Run Code Online (Sandbox Code Playgroud)
然后我创建列表并设置数组长度如下
MyList:=TList<TMyRec>.Create;
SetLength(MyRec.MyArr,5);
MyRec.MyArr[0]:=8; // just for demonstration
MyRec.Name:='Record 1';
MyRec.Completed:=true;
MyList.Add(MyRec);
Run Code Online (Sandbox Code Playgroud)
然后我更改数据MyArr
,我也更改MyRec.Name
并将另一个项目添加到列表中
MyRec.MyArr[0]:=5; // just for demonstration
MyRec.Name:='Record 2';
MyRec.Completed:=false;
MyList.Add(MyRec);
Run Code Online (Sandbox Code Playgroud)
当MyRec.MyArr
将第一个项目添加到列表后发生变化时,MyArr
存储到列表中的内容也会发生变化。但是其他记录字段没有。
我的问题是如何防止更改MyRec.MyArr
反映在已存储在列表项中的数组上。
我需要声明多条记录吗?
这个例子可以像这样简化,删除所有对泛型的引用:
{$APPTYPE CONSOLE}
var
x, y: array of Integer;
begin
SetLength(x, 1);
x[0] := 42;
y := x;
Writeln(x[0]);
y[0] := 666;
Writeln(x[0]);
end.
Run Code Online (Sandbox Code Playgroud)
输出是:
42 第666章
原因是动态数组是引用类型。当您分配给动态数组类型的变量时,您将获取另一个引用而不是进行复制。
您可以通过强制引用唯一(即只有一个简单的引用)来解决此问题。有多种方法可以实现这一目标。例如,您可以调用SetLength
您想要唯一的数组。
{$APPTYPE CONSOLE}
var
x, y: array of Integer;
begin
SetLength(x, 1);
x[0] := 42;
y := x;
SetLength(y, Length(y));
Writeln(x[0]);
y[0] := 666;
Writeln(x[0]);
end.
Run Code Online (Sandbox Code Playgroud)
输出:
42 42
所以,在你的代码中你可以这样写:
MyList:=TList<TMyRec>.Create;
SetLength(MyRec.MyArr,5);
MyRec.MyArr[0]:=8; // just for demonstration
MyRec.Name:='Record 1';
MyRec.Completed:=true;
MyList.Add(MyRec);
SetLength(MyRec.MyArr,5); // <-- make the array unique
MyRec.MyArr[0]:=5; // just for demonstration
MyRec.Name:='Record 2';
MyRec.Completed:=false;
MyList.Add(MyRec);
Run Code Online (Sandbox Code Playgroud)
您可以使用各种其他方法来强制唯一性,包括Finalize
、 分配nil
、Copy
等。
文档中详细介绍了这个问题。以下是相关摘录:
如果 X 和 Y 是相同动态数组类型的变量,则 X := Y 将 X 指向与 Y 相同的数组。(在执行此操作之前不需要为 X 分配内存。)与字符串和静态数组不同,复制-on-write 不适用于动态数组,因此在写入之前不会自动复制它们。例如,这段代码执行后:
Run Code Online (Sandbox Code Playgroud)var A, B: array of Integer; begin SetLength(A, 1); A[0] := 1; B := A; B[0] := 2; end;
A[0] 的值为 2。(如果 A 和 B 是静态数组,A[0] 仍为 1。)分配给动态数组索引(例如,MyFlexibleArray[2] := 7)不会重新分配数组。编译时不会报告超出范围的索引。相反,要制作动态数组的独立副本,必须使用全局 Copy 函数:
Run Code Online (Sandbox Code Playgroud)var A, B: array of Integer; begin SetLength(A, 1); A[0] := 1; B := Copy(A); B[0] := 2; { B[0] <> A[0] } end;
归档时间: |
|
查看次数: |
3970 次 |
最近记录: |