확장 레코드 열거자 — 레코드에 for..in 반복 부여하기

확장 레코드 열거자 — 레코드에 for..in 반복 부여하기

확장 레코드는 열거자(enumerator)를 가질 수 있어요. 그러려면 열거자 레코드를 반환하는 함수를 확장 레코드 안에 정의해야 해요.

출처: Extended record enumerators — Free Pascal Reference

본문

{$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를 참고하세요