如何修改 TList<record> 的值?

13

Delphi 2010 如何修改 TList<record> 中的值?

type TTest = record a,b,c:Integer end;
var List:TList<TTest>;
    A:TTest;
    P:Pointer;
....
....

List[10] := A;  <- OK
List[10].a:=1;  <- Here compiler error : Left side cannot be assined to
P:=@List[10];   <- Error: Variable requied

荒谬的错误,却没有人愿意教授。他们编写文档的方式真是可耻。 - user30478
4个回答

11
A := List[10];
A.a := 1;
list[10] := A;

你不必使用对象来完成此操作,因为它们是引用类型(通过指针访问,编译器会在内部管理指针以避免使您感到困扰),但记录是值类型,所以不能这样做。


这是一种简单而强大的方法。但是当记录的大小非常巨大时,由于局部变量A,堆栈会溢出,如果在循环或多重循环中使用,速度非常慢。 - JO SeongGng

10

你在使用记录时遇到了问题。

考虑以下代码:

function Test: TTest;
begin
    ...
end;

Test.a := 1;

你的代码在编译器看来实际上是这样的:

TTest temp := Test;
temp.a := 1;
编译器通过错误信息告诉你,这个赋值是无意义的,因为它只会将一个新的值分配给一个暂时的记录值,该值将被立即遗忘。
此外,@List[10] 是无效的,因为 List[10] 再次仅返回一个临时的记录值,因此获取该记录的地址是相当无意义的。
然而,读写整个记录是可以的。
因此,总结一下:
List[10] := A;  <- writing a whole record is OK
List[10].a:=1;  <- List[10] returns a temporary record, pointless assignment
P:=@List[10];   <- List[10] returns a temporary record, its address is pointless

2
然而,属性items是可读写的,我认为Delphi可以理解Items[1].a:=123表示Items[1]:=TType(123,oldval2,oldval3)。 - Astronavigator
但这并不是重点... 重要的部分不是编译器 可以 做什么,而是它 实际上 做了什么。 - Lasse V. Karlsen
1
@Astronavigator:是的,该属性是可读写的,但您并没有直接访问该字段。它只返回该字段的副本。请查看Mason的答案以解决此问题。 - Ken Bourassa

2

如果您想存储记录,动态数组更适合处理它们:

type TTest = record a,b,c : Integer end;
type TTestList = array of TTest;
var List:TTestList;
    A:TTest;
    P:Pointer;
....
....

SetLength( List, 20 );
List[10]   := A; //<- OK
List[10].a := 1; //<- Ok
P := @List[10];  //<- Not advised (the next SetLength(List,xx) will blow the address away),
                 //   but technically works

如果您需要添加用于操作这些数据的方法,您可以将此数组存储为类的字段,并将您的方法添加到该类中。


0
如果您需要操作该表单中的对象,最好使用TObjectList而不是TList,并将结构定义为类而不是记录:
type TTest = class a,b,c:Integer end;
var List:TObjectList<TTest>;
    A:TTest; // A is an object so there's no need for a pointer
....
....
List.Add(TTest.Create);
List.Last.a := 1;
A:=List.Last;

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