확장 레코드 열거자 — 레코드에 for..in 반복 부여하기
확장 레코드 열거자 — 레코드에 for..in 반복 부여하기
확장 레코드는 열거자(enumerator)를 가질 수 있어요. 그러려면 열거자 레코드를 반환하는 함수를 확장 레코드 안에 정의해야 해요.
본문
{$mode objfpc}
{$modeswitch advancedrecords}
type
TIntArray = array[0..3] of Integer;
TEnumerator = record
private
FIndex: Integer;
FArray: TIntArray;
function GetCurrent: Integer;
public
function MoveNext: Boolean;
property Current: Integer read GetCurrent;
end;
TMyArray = record
F: array[0..3] of Integer;
function GetEnumerator: TEnumerator;
end;
function TEnumerator.MoveNext: Boolean;
begin
inc(FIndex);
Result := FIndex < Length(FArray);
end;
function TEnumerator.GetCurrent: Integer;
begin
Result := FArray[FIndex];
end;
function TMyArray.GetEnumerator: TEnumerator;
begin
Result.FArray := F;
Result.FIndex := -1;
end;
이 정의들 다음에 아래 코드는 컴파일되고 F 안의 모든 요소를 열거해요.
var
Arr: TMyArray;
I: Integer;
begin
for I in Arr do
WriteLn(I);
end.
열거자 연산자로 달성하기
같은 효과를 열거자 연산자(enumerator operator)로도 낼 수 있어요.
{$mode objfpc}
{$modeswitch advancedrecords}
type
TIntArray = array[0..3] of Integer;
TEnumerator = record
private
FIndex: Integer;
FArray: TIntArray;
function GetCurrent: Integer;
public
function MoveNext: Boolean;
property Current: Integer read GetCurrent;
end;
TMyArray = record
F: array[0..3] of Integer;
end;
function TEnumerator.MoveNext: Boolean;
begin
inc(FIndex);
Result := FIndex < Length(FArray);
end;
function TEnumerator.GetCurrent: Integer;
begin
Result := FArray[FIndex];
end;
operator Enumerator(const A: TMyArray): TEnumerator;
begin
Result.FArray := A.F;
Result.FIndex := -1;
end;
이렇게 하면 같은 코드도 동작하게 돼요.
핵심을 정리하면 이래요. 첫 번째 방식은 레코드 자체에 GetEnumerator 메서드를 정의하는 것이고, 두 번째 방식은 Enumerator 연산자를 정의해서 레코드에 붙이는 거예요. for I in Arr do 문은 컴파일러가 GetEnumerator(또는 Enumerator 연산자)로부터 열거자 객체를 얻고, MoveNext가 false를 반환할 때까지 Current를 하나씩 순회해요.
더 알아보기
- 확장 레코드의 기초는 Definition에서 다뤄요
- 확장 레코드의 연산자 정의는 Record operators를 참고하세요