Enumerators & for-in
for X in Container do works for arrays, strings, sets, and any type that provides GetEnumerator, returning an object or record with:
32.1 What for-in needs
for X in Container do works for arrays, strings, sets, and any type that provides GetEnumerator, returning an object or record with:
a function MoveNext: Boolean a property Current: T (read-only)
32.2 A range enumerator
program RangeEnum;
{$IFDEF FPC}{$mode delphi}{$ENDIF}
{$APPTYPE CONSOLE}
type
TRangeEnumerator = record
private
FCurrent, FLast, FStep: Integer;
public
function MoveNext: Boolean;
property Current: Integer read FCurrent;
end;
TRange = record
First, Last, Step: Integer;
function GetEnumerator: TRangeEnumerator;
end;
function TRangeEnumerator.MoveNext: Boolean;
begin
Inc(FCurrent, FStep);
Result := FCurrent <= FLast;
end;
function TRange.GetEnumerator: TRangeEnumerator;
begin
Result.FCurrent := First - Step; // MoveNext is called before the first Current
Result.FLast := Last;
Result.FStep := Step;
end;
function Range(AFirst, ALast: Integer; AStep: Integer = 1): TRange;
begin
Result.First := AFirst;
Result.Last := ALast;
Result.Step := AStep;
end;
var
I: Integer;
begin
for I in Range(0, 20, 5) do
Write(I, ' '); // 0 5 10 15 20
Writeln;
end.32.3 Enumerating a custom collection
type
TNode = class
Value: string;
Next: TNode;
end;
TLinkedList = class;
TLinkedListEnumerator = class
private
FCurrent: TNode;
FStarted: Boolean;
FList: TLinkedList;
function GetCurrent: string;
public
constructor Create(AList: TLinkedList);
function MoveNext: Boolean;
property Current: string read GetCurrent;
end;
TLinkedList = class
private
FHead: TNode;
public
procedure AddFirst(const S: string);
function GetEnumerator: TLinkedListEnumerator; // for-in frees a class enumerator automatically
end;
constructor TLinkedListEnumerator.Create(AList: TLinkedList);
begin
inherited Create;
FList := AList;
end;
function TLinkedListEnumerator.MoveNext: Boolean;
begin
if not FStarted then
begin
FCurrent := FList.FHead;
FStarted := True;
end
else
FCurrent := FCurrent.Next;
Result := FCurrent <> nil;
end;
function TLinkedListEnumerator.GetCurrent: string;
begin
Result := FCurrent.Value;
end;
procedure TLinkedList.AddFirst(const S: string);
var
N: TNode;
begin
N := TNode.Create;
N.Value := S;
N.Next := FHead;
FHead := N;
end;
function TLinkedList.GetEnumerator: TLinkedListEnume
…32.4 Built-in enumerable types
static/dynamic arrays members in ordinal order TList, TCollection, TComponent (owned components) TList<T>, TQueue<T>, TStack<T>
TPair<K,V>; also .Keys and .Values FPC: any type with an operator enumerator
Do not modify a collection (add/remove items) while enumerating it — collections raise exceptions or behave unpredictably. Iterate backwards with an index loop when deleting.