제네릭 타입 제약(Generic Type Restrictions)
제네릭 타입 제약(Generic Type Restrictions)
제네릭을 정의할 때 자리표시자 타입이 너무 자유로우면 쓸 때마다 매번 검증에 막혀요. 그래서 템플릿 타입에 "이 클래스에서 파생되어야 한다", "이 인터페이스를 구현해야 한다" 같은 제약을 걸 수 있어요. 걸어 두면 특수화가 훨씬 안전해져요.
본문
8.1 절(432쪽)의 다이어그램을 보면 타입 템플릿 목록이 타입에 대한 추가 지정자를 가질 수 있어요. 이건 특히 객체 타입에서 유용해요. 템플릿 타입이 특정 클래스에서 파생되어야 한다면, 그걸 템플릿 목록에서 지정할 수 있어요.
{$mode objfpc}
{$h+}
uses sysutils, classes;
Type
generic TList<_T : TComponent> = class(TObject)
public
Type TCompareFunc = function(const Item1, Item2: _T): Integer;
Public
data : _T;
procedure Add(item: _T);
procedure Sort(compare: TCompareFunc);
end;
위 정의를 기준으로, 아래는 컴파일돼요.
TPersistentList = specialize TList<TComponent>;
하지만 아래는 컴파일되지 않아요.
TPersistentList = specialize TList<TPersistent>;
컴파일러는 에러를 내요.
Error: Incompatible types: got "TPersistent" expected "TComponent"
여러 타입을 함께 묶을 수도 있어요. 콜론 뒤에 클래스 제약을 적어서요.
Type
generic TList<Key1,Key2 : TComponent; Value1 : TObject> = class(TObject)
또한 클래스 제약과 인터페이스 제약에 대해 타입 식별자를 둘 이상 지정할 수도 있어요. 클래스가 지정되면 템플릿에 쓰는 타입은 그 타입과 같거나 그 타입에서 파생되어야 해요.
Type
generic TList<T: TComponent, IEnumerable> = class(TObject)
T를 특수화하는 데 쓰는 클래스는 TComponent에서 파생되고 IEnumerable을 구현해야 해요. 인터페이스가 지정되면 템플릿 타입은 최소한 그 인터페이스를 구현해야 해요. 단 그 인터페이스의 하위 인터페이스여도 문제없어요.
Type
generic TGenList<T: IEnumerable> = class(TObject)
IMyEnum = Interface (IEnumerable)
Procedure DoMy;
end;
TList = specialize TGenList<IMyEnum>;
TSomeList = Specialize TGenList<TList>;
인터페이스는 여러 개 지정할 수 있어요. 그 경우 클래스 타입은 나열된 인터페이스를 모두 구현해야 해요. 클래스 이름 하나에 인터페이스 이름 여러 개를 섞는 것도 가능해요.
타입 제약이 없으면, 컴파일러는 템플릿 타입들이 할당 호환되지 않는다고 가정해요. 이건 제네릭 클래스에 오버로드된 메서드가 있을 때 특히 중요해요. 다음 제네릭 타입 선언을 볼게요.
type
generic TTest<T1, T2> = class
procedure Test(aArg: LongInt);
procedure Test(aArg: T1);
procedure Test(aArg: T2);
end;
위를 특수화하는 것은, T1과 T2가 서로 다른 두 타입이고 둘 다 LongInt가 아닐 때만 컴파일돼요. 아래는 컴파일돼요.
T1 = specialize TTest<String, TObject>;
하지만 아래 두 개는 컴파일되지 않아요.
T2 = specialize TTest<String, String>;
또는
T2 = specialize TTest<String, Longint>;
T1과 T2가 구분이 안 되기 때문이에요.
더 알아보기
- 제네릭 타입을 정의하는 기본 방법은 8.2 절에서 다뤄요.
- 제네릭을 특수화하는 방법은 8.3 절에서 확인할 수 있어요.
- 제네릭의 2단계 과정은 8.1 절(제네릭 소개)을 참고해요.