开发者

Using "for in" sentence and compiler error E2064

I want to use for in sentence in my test case under D2010.

If I want to write in Param.Value variable then compiler reports error 2064, but allows to write in Par开发者_StackOverflow中文版am.Edit.text from the same record, why?

TEST CASE:

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;


Records are value types. The for in loop is returning a copy of each record in the array and so the compiler error is actually telling you that modifying it is futile.

You'll need to use an old fashioned for loop:

for i := low(dtcp) to high(dtcp) do
  dtcp[i].Value := 0;


There are some problems with records returned by a function. (The iterator uses a function). The compiler error can be solved using an extra variable:

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

But this still doesn't update the dtcp array. Which isn't strange because records are copied and the copy is updated. You can solve this by using classes (or pointers to records):

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

Now the original code works. But don't forget to create and destroy the classes.

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;


Records are value-types, not reference-types. In your case Param is not a record from the array, but a copy of a record from the array. That's why the compiler considers it a constant, and prevents you to assign value to a temporary copy of a record.


Record types are value types; For the simple case, let's assume you're using the for in loop over a TList<TRecordType>. Since the iterator is a function, it will return a copy of the record in the list. Changing that copy has no effect over the record in the list; Even if the compiler allowed you to do that, as it did in older versions of Delphi, the result would not be the one you expect.

Think of a function returning a plain Integer (also a value type). You'd never think of writing code like this, because intuition tells you it doesn't make sense:

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;

... yet the situation is the same with a record. Imagine this example:

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;

The situation is the same with the for in loop. The iterator itself uses a property that's most likely implemented with a function. Since changing the result of a function makes very little sense, and considering the change would not be propagated back to wherever the iterator got it's value, the compiler is doing very well to stop it!


Yes, records are value types, so you receive a copy, but that is not the real problem. The main problem is that the value returned by the for-in loop is very likely to be a function result, and the compiler doesn't allow you to write to a function result. The same applies to, for instance, properties.

If the function result is a reference type, e.g. a typed pointer or an object, you can write to its properties, but you can't change the item itself. If the function is a value type, you can#t write to parts of it either.

You could of course assign the value to a variable, and update that,but like others said, you will not be modifying the original value.

This all means that for-in loops should only be used to read from things like arrays, lists, sets, collections, etc. and never to write to them.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜