3

我想在 D2010 下的测试用例中使用for in sentence。

如果我想写入Param.Value变量,那么编译器会报告错误 2064,但允许从同一记录写入Param.Edit.text ,为什么?

测试用例:

type
//
  TparamSet = (param_A, param_B, param_C, param_D, param_E, param_F);

  TParam = record
    Edit        :TEdit;
    Value       :integer;
  end;

var
  dtcp                  :array [TparamSet] of TParam;

procedure ResetParams;
var
  Param                 :TParam;
  A                     :Integer;
begin
  for Param in dtcp do
  begin
    Param.Edit.text:= 'Test';             //No problem
    A := Param.Value;                     //No problem
    Param.Value := 0;                     //Error: E2064 Left side cannot be assigned to;
  end;
end;
4

5 回答 5

9

记录是值类型。循环返回数组中每条记录的for in副本,因此编译器错误实际上告诉您修改它是徒劳的。

您需要使用老式的 for 循环:

for i := low(dtcp) to high(dtcp) do
  dtcp[i].Value := 0;
于 2011-07-13T08:41:33.537 回答
3

函数返回的记录存在一些问题。(迭代器使用一个函数)。编译器错误可以使用一个额外的变量来解决:

    Param2 := Param;
    Param2.Value := 0;                     // This works (D2010)

但这仍然不会更新 dtcp 数组。这并不奇怪,因为记录被复制并且副本被更新。您可以通过使用类(或指向记录的指针)来解决此问题:

TParam = class
  Edit        :TEdit;
  Value       :integer;
end;

现在原始代码可以工作了。但不要忘记创建和销毁类。

procedure ResetParams;
var
  Param                 :TParam;
  A                     :Integer;
begin
  for Param in dtcp do
  begin
    Param.Edit.text:= 'Test';             //No problem
    A := Param.Value;                     //No problem
    Param.Value := 0;                     // This works (D2010)
  end;
end;
于 2011-07-13T08:31:08.113 回答
2

记录是值类型,而不是引用类型。在您的情况下Param,不是数组中的记录,而是数组中记录的副本。这就是编译器将其视为常量并阻止您为记录的临时副本赋值的原因。

于 2011-07-13T08:39:43.237 回答
2

记录类型是值类型;对于简单的情况,假设您在for ina 上使用循环TList<TRecordType>。由于迭代器是一个函数,它将返回列表中记录的副本。更改该副本对列表中的记录没有影响;即使编译器允许你这样做,就像在旧版本的 Delphi 中那样,结果也不会是你所期望的。

想想一个函数返回一个普通的Integer(也是一个值类型)。你永远不会想到写这样的代码,因为直觉告诉你这没有意义:

function aFunc(aParam:Integer): Integer;
begin
  Result := 7;
end;

procedure Test;
begin
  aFunc(8) := 9; // This doesn't compile and intuition tells you it's *very* wrong.
end;

...但情况与记录相同。想象一下这个例子:

type TTestRecord = record
  aField: Integer;
end;

function TestFunc: TTestRecord;
begin
  Result.aField := 9;
end;

procedure TestProc;
begin
  TestFunc.aField := 10; // This also doesn't make any sense, but intuition might
                         // fail on this one. Older versions of the compiler allowed this!
end;

情况与for in循环相同。迭代器本身使用最有可能通过函数实现的属性。由于更改函数的结果几乎没有意义,并且考虑到更改不会传播回迭代器获得其值的任何地方,编译器在阻止它方面做得很好!

于 2011-07-13T08:45:32.897 回答
0

是的,记录是值类型,因此您会收到一份副本,但这不是真正的问题。主要问题是for-in循环返回的值很可能是函数结果,编译器不允许你写入函数结果。例如,这同样适用于属性。

如果函数结果是引用类型,例如类型化指针或对象,您可以写入其属性,但不能更改项目本身。如果函数是一个值类型,你也不能写入它的一部分。

您当然可以将值分配给变量,然后更新它,但就像其他人所说的那样,您不会修改原始值。

这一切都意味着 for-in 循环只能用于读取数组、列表、集合、集合等内容,而永远不要写入它们。

于 2011-07-13T20:20:35.860 回答