ジェネリックスでは渡される型パラメータに関する制約を指定することができます。
ジェネリックスの制約 - RAD Studio XE3
ここで制約としてインタフェース型またはクラス型を指定すると型パラメータは必然的にそのクラス型、インタフェース型になります。またconstructorを指定すると型パラメータはクラス型になります(レコード型はパラメータを持たないコンストラクタを定義できないため)。classを指定するとこれもまたクラス型、インタフェース型になります(ヘルプ参照)。
では最後に残ったrecordを指定(レコード指定)した場合、型パラメータに許される型はレコード型だけなのでしょうか?実際にはレコード型だけではなく、いわゆる値型(参照型ではないもの)であればいいようで、IntegerやCardinal、あるいは部分範囲型や列挙型も指定することができます。
type
TConstraintTest<T: record> = record
class procedure TestProc(Value: Integer); static;
end;
class procedure TConstraintTest<T>.TestProc(Value: Integer);
begin
{ No operation }
end;
このようなジェネリックスを定義すると、type
TTestRange = 1..5;
TTestEnum = (One, Two, Three);
begin
TConstraintTest<TPoint>.TestProc(0);
TConstraintTest<Integer>.TestProc(0);
TConstraintTest<Cardinal>.TestProc(0);
TConstraintTest<TTestRange>.TestProc(0);
TConstraintTest<TTestEnum>.TestProc(0);
end;
これらはすべて正しくコンパイルされます。ただしString型は参照型でありながらクラス型ではないため、constructor以外の制約を指定された型パラメータにStringを指定するとコンパイルエラーになります("class"を指定すると
E2511 型パラメータ 'T' はクラス型が必要です、"record"を指定すると
E2512 型パラメータ 'T' は非 null 値型が必要ですとなる)。つまり文字列型を受け入れるためには型パラメータに制約を指定しないか、constructor制約を指定するかのいずれかが必要ということになります。
元ねたはDelphi XE2 Foundations。
2013/07/03追記: constructor制約については細川さんによる考察が参考になります。
0 件のコメント:
コメントを投稿