型パラメータと型制約
型パラメータは将来の型引数のプレースホルダーであり、_型変数_のように動作します。その値はコンパイル時に分かっており、名前付き定数が数値、文字列、またはbool値を表すのと似ています。通常の変数と同様、型パラメータには型があります。その型は_型制約_によって記述され、型制約は各型パラメータの型に対してどのような操作が許可されるかを決定します。
型パラメータをインスタンス化する具体的な型は、その型パラメータの制約を満たす必要があります。これにより、型パラメータの型を持つ操作数が、型パラメータをインスタンス化するために使用される具体的な型が何であっても、各型制約のすべてのプロパティを持つことが保証されます。
Goでは、型制約はメソッド要件と型要件の混合により記述され、これらが一緒になって_型セット_を定義します。これは、すべての要件を満たすすべての型のセットです。Goはこの目的のために、インターフェースの一般化された形式を使用します。インターフェースは一連のメソッドと型を列挙し、このようなインターフェースによって記述される型セットは、それらのメソッドを実装し、列挙された型に含まれるすべての型で構成されます。
たとえば、以下のインターフェースによって記述される型セット:
type Constraint interface {
~[]byte | ~string
Hash() uint64
}
は、表現が[]byte
またはstring
で、メソッドセットにHash
メソッドを含むすべての型で構成されます。
これにより、ジェネリック操作数に対する操作を制御するルールを記述できます。たとえば、インデックス式のルールは、型パラメータ型P
の操作数a
について(他の条件の中で)以下のように述べています:
インデックス式
a[x]
は、P
の型セット内のすべての型の値に対して有効でなければなりません。P
の型セット内のすべての型の要素型は同一でなければなりません。(この文脈では、string型の要素型はbyte
です。)
これらのルールにより、以下のジェネリック変数s
をインデックスすることが可能になります(playground):
func at[bytestring Constraint](s bytestring, i int) byte {
return s[i]
}
インデックス操作s[i]
が許可されるのは、s
の型がbytestring
であり、bytestring
の型制約(型セット)に[]byte
とstring
型が含まれており、これらに対してi
によるインデックスが有効だからです。