Arrays 包含动态数组的记录的常规列表
我有一个通用的记录列表。这些记录包含一个动态数组,如下所示Arrays 包含动态数组的记录的常规列表,arrays,delphi,generics,record,tlist,Arrays,Delphi,Generics,Record,Tlist,我有一个通用的记录列表。这些记录包含一个动态数组,如下所示 Type TMyRec=record MyArr:Array of Integer; Name: string; Completed: Boolean; end; var MyList:TList<TMyRec>; MyRec:TMyRec; 将第一个项目添加到列表后,MyRec.MyArr更改时,存储到列表中的MyArr也会更改。但是,其他记录字段没有 我的问题是如何防止MyRec.My
Type
TMyRec=record
MyArr:Array of Integer;
Name: string;
Completed: Boolean;
end;
var
MyList:TList<TMyRec>;
MyRec:TMyRec;
将第一个项目添加到列表后,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.
输出为:
42
666
输出:
42
42
[0]的值为2。(如果A和B是静态数组,则A[0]将
仍然是1。)分配给动态数组索引(例如,
MyFlexibleArray[2]:=7)不重新分配数组。超出范围
在编译时不报告索引。相比之下,作出
动态数组的独立副本,必须使用全局副本
功能:
var
A, B: array of Integer;
begin
SetLength(A, 1);
A[0] := 1;
B := Copy(A);
B[0] := 2; { B[0] <> A[0] }
end;
var
A、 B:整数数组;
开始
设定长度(A,1);
A[0]:=1;
B:=副本(A);
B[0]:=2;{B[0]A[0]}
结束;
…以下是对原始问题争议的观察
至于其余的,我更喜欢在你添加值后立即断开变量和列表之间的链接。几个月后,你会忘记你的问题,也许会重构你的程序。如果将第二个SetLength
放在列表之外。添加
,您可能会忘记该记录仍然包含对列表中相同数组的引用
TMyRec=record
MyArr: TArray< double >; // making it 1D for simplicity
Name: string;
Completed: Boolean;
end;
SetLength(MyRec.MyArr,5);
MyRec.MyArr[0]:=8; // just for demonstration
MyRec.Name:='Record 1';
MyRec.Completed:=true;
MyList.Add(MyRec);
MyRec.MyArr := nil; // breaking the parasite link immediately!
现在,最后一个选项是将使用的代码压缩成一个过程,您可以多次调用该过程。然后变量将变成本地变量,Delphi将自动为您完成它
Procedure AddRec( const Name: string; const Compl: boolean; const Data: array of double);
var i: integer; MyRec: TMyRec;
begin
SetLength(MyRec.MyArr, Length( Data ) );
for i := 0 to Length(Data) - 1 do
MyRec.MyArr[i] := Data [i];
MyRec.Name := Name;
MyRec.Completed := Compl;
MyList.Add(MyRec);
end;
MyList:=TMyList<TMyRec>.create;
AddRec( 'Record 1', True , [ 8 ]);
AddRec( 'Record 2', False, [ 5 ]);
...
Procedure AddRec(常量名称:string;常量Compl:boolean;常量数据:double数组);
varⅠ:整数;MyRec:TMyRec;
开始
设置长度(MyRec.MyArr,长度(数据));
对于i:=0到长度(数据)-1 do
MyRec.MyArr[i]:=数据[i];
MyRec.Name:=名称;
MyRec.Completed:=完成的组件;
MyList.Add(MyRec);
结束;
MyList:=TMyList.create;
AddRec('Record 1',True[8]);
AddRec('Record 2',False,[5]);
...
由于
MyRec
现在是一个局部变量,它在退出AddRec
时会被破坏,它不会保留到数组的链接,也不会影响您或任何其他使用您的类型的开发人员。只需在旧变量中创建一个新变量,一切都应该正常
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);
MyRec := TMyRec.Create();
SetLength(MyRec.MyArr,5);
MyRec.MyArr[0]:=5; // just for demonstration
MyRec.Name:='Record 2';
MyRec.Completed:=false;
MyList.Add(MyRec);
MyList:=TList.Create;
设定长度(MyRec.MyArr,5);
MyRec.MyArr[0]:=8;//只是为了示范
MyRec.Name:=“记录1”;
MyRec.Completed:=真;
MyList.Add(MyRec);
MyRec:=TMyRec.Create();
设定长度(MyRec.MyArr,5);
MyRec.MyArr[0]:=5;//只是为了示范
MyRec.Name:=“记录2”;
MyRec.Completed:=false;
MyList.Add(MyRec);
我刚修好了question@DavidHeffernan但你不知道这个话题的真正含义。这两个部分相互矛盾,你自己决定哪一个是错的。我认为这是值得的,如果他放弃堆栈溢出,那么让这个问题对任何人有利,而不是对逃跑的TS有利是有意义的。但是TS在这里,他可以按照他真正的意图解决这个问题。这是我的错误MyArr:整数数组
是正确的偏差。问题被修改为David@DavidHeffernan你能在答案中加上零、最终和局部风险值吗?那我的就可以了deleted@DavidHeffernan嗯,提到他们“他们存在”并不是在举例说明利弊。不能同意你已经做了:-)甚至没有提到本地变量。也没有立即中断链接。+1,我很好奇为什么没有直接的语言元素来进行深度复制Clone()
是个好名字。或者介绍COW动态数组(我已经有了)。@LURD深度复制是一件很容易说,但很难做的事情。在语言级别上,您需要每种类型都能够执行深度复制。这对指针意味着什么?也许类型化指针是可行的,但非类型化指针呢?如何深度复制接口?所以我认为它本质上是硬的。谢谢你的紫外线顺便说一句。我必须说,在这里投票很奇怪。更多人投票支持非答案。@lurd可能是因为字符串由简单字符组成,但数组可以由对象、接口和谁知道是什么组成。它将隐藏导致失败期望的复杂性,比如本主题开头的期望。对于字符串、接口等,只需增加引用计数。未类型化的指针将保留在野外,但与Copy()命令没有区别。@alcalde Python类型确实需要实现钩子才能使deepcopy工作。钩子定义得很好,但它们需要演员的合作。它没有创建方法。没有解释的答案永远都不理想。编程应该是理解而不是魔法咒语。
var
A, B: array of Integer;
begin
SetLength(A, 1);
A[0] := 1;
B := A;
B[0] := 2;
end;
var
A, B: array of Integer;
begin
SetLength(A, 1);
A[0] := 1;
B := Copy(A);
B[0] := 2; { B[0] <> A[0] }
end;
TMyRec=record
MyArr: TArray< double >; // making it 1D for simplicity
Name: string;
Completed: Boolean;
end;
SetLength(MyRec.MyArr,5);
MyRec.MyArr[0]:=8; // just for demonstration
MyRec.Name:='Record 1';
MyRec.Completed:=true;
MyList.Add(MyRec);
MyRec.MyArr := nil; // breaking the parasite link immediately!
SetLength(MyRec.MyArr,5);
MyRec.MyArr[0]:=8; // just for demonstration
MyRec.Name:='Record 1';
MyRec.Completed:=true;
MyList.Add(MyRec);
Finalyze(MyRec); // breaking all the parasite links immediately!
Procedure AddRec( const Name: string; const Compl: boolean; const Data: array of double);
var i: integer; MyRec: TMyRec;
begin
SetLength(MyRec.MyArr, Length( Data ) );
for i := 0 to Length(Data) - 1 do
MyRec.MyArr[i] := Data [i];
MyRec.Name := Name;
MyRec.Completed := Compl;
MyList.Add(MyRec);
end;
MyList:=TMyList<TMyRec>.create;
AddRec( 'Record 1', True , [ 8 ]);
AddRec( 'Record 2', False, [ 5 ]);
...
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);
MyRec := TMyRec.Create();
SetLength(MyRec.MyArr,5);
MyRec.MyArr[0]:=5; // just for demonstration
MyRec.Name:='Record 2';
MyRec.Completed:=false;
MyList.Add(MyRec);