For..in..do
В язык Delphi добавлена конструкция for..in..do для перебора всех членов массива, строки, множества или коллекции.
- for Element in ArrayExpr do Stmt;
- for Element in StringExpr do Stmt;
- for Element in SetExpr do Stmt;
- for Element in CollectionExpr do Stmt;
То есть, в цикле перебираются все элементы некоего множества и для каждого выполняется тело цикла. Например, теперь ничего не стоит перевернуть строку наоборот (см. )
Полная и весьма понятная информация находится в справке, смотрите раздел "Declarations and Statements"
Наиболее интересным применением циклов такого вида является их использование с коллекциями для перебора элементов. Для того, чтобы класс можно было использовать с циклами for..in, класс должен реализовать предопределенный паттерн коллекции. А именно, класс должен удовлетворять следующим требованиям:
- содержать public метод экземпляра с именем GetEnumerator, который должен возвращать экземпляр класса, ссылку на интерфейс или запись (record).
- экземпляр класса, ссылка на интерфейс или запись, возвращенные методом GetEnumerator, должны содержать public метод экземпляра с именем MoveNext, возвращающий значение типа boolean.
- экземпляр класса, ссылка на интерфейс или запись, возвращенные методом GetEnumerator должны содержать public свойство экземпляра с именем Current, тип которого должен соответствовать типу элементов контейнера.
Экземпляр, возвращенный методом GetEnumerator, автоматически разрушается после окончания цикла for..in.
Следующий пример показывает реализацию паттерна коллекции
program Project1; {$APPTYPE CONSOLE} type TMyIntArray = array of Integer; TMyEnumerator = class Values: TMyIntArray; Index: Integer; public constructor Create; function GetCurrent: Integer; function MoveNext: Boolean; property Current: Integer read GetCurrent; end; TMyContainer = class public function GetEnumerator: TMyEnumerator; end; constructor TMyEnumerator.Create; begin inherited Create; Values := TMyIntArray.Create(100, 200, 300); Index := -1; end; function TMyEnumerator.MoveNext: Boolean; begin if Index < High(Values) then begin Inc(Index); Result := True; end else Result := False; end; function TMyEnumerator.GetCurrent: Integer; begin Result := Values[Index]; end; function TMyContainer.GetEnumerator: TMyEnumerator; begin Result := TMyEnumerator.Create; end; var MyContainer: TMyContainer; I: Integer; Counter: Integer; ar: TMyIntArray; begin MyContainer := TMyContainer.Create; Counter := 0; for I in MyContainer do Inc(Counter, I); WriteLn('Counter = ', Counter); end.
Поддержка синтаксиса for...in уже встроена в ряд классов VCL, например, TList, TComponent, TCollection, и т.д. - в общей сложности около 15 классов. Так, например, перечисление имен компонентов формы может выглядеть следующим образом (хотя и непривычно):
var I: TComponent; begin for I in Self do ListBox.Add (I.Name); end;