総称型 / ジェネリクス

値の型として、例えば単なる「リスト」ではなく、「整数のリスト」や、「文字列のリストのリスト」など、要素の型も指定できるような機能。要素の型の部分を型パラメータと言ったりする。

C++

クラステンプレートや関数テンプレートの機能があるが、詳細はもう忘れた。

型パラメータの表記はJavaと似ていて、<...> を使う。

Java

Genericsとか総称型とも言ったりする。

「整数のリスト」は List<Integer> のように書く。

Java7からは <...> の内側を省略できる場合もあり、中身が省略された <> をダイアモンド演算子という。

インスタンス生成の例

Map<String, List<Integer>> map = new HashMap<>();

クラス定義の例

public class FooClass<A, B> extends SuperClass {
    ...
}

メソッド定義の例

public <A, B> B bar(A a) {
    ...
}

Scala

Javaでは型パラメータを囲むのに <> を使っているが、 Scalaでは [] を使う。

val map: Map[String, List[Int]] = Map.empty;

クラス定義でのジェネリクス

Java

public class Foo<T1, T2> {
    
    ...
    
}

Scala

class Foo[T1, T2] {
    
    ...
    
}

メソッド定義でのジェネリクス

クラス定義に存在する型パラメータはそのままメソッド定義でも使える。

クラス定義に存在する型パラメータをメソッド単位で新たに導入したい場合には、メソッド定義で型パラメータを宣言する。

Java

public <T1, T2> T1 bar(T2: arg) {
    ...;
}

Scala

def bar[T1, T2](T2: arg): T1 = {
    ...;
}

型パラメータの制約の宣言

型パラメータに当てはまる型を、特定の型またはそれを継承する型(子クラス、孫クラス、、、)に限定したい場合に、それを上限境界という。

逆に、型パラメータに当てはまる型を、特定の型またはそれの親となる型(親クラス、祖父母クラス、、、)に限定したい場合に、それを下限境界という。

Scalaではさらに、ダックタイピングみたいに、特定のシグニチャのメソッドを実装している型という制約もできる。

Java

<T exnteds Bar>BarまたはBarの任意のサブクラスを表す。

上限境界の例

public class Foo<T1 extends Bar, T2> {
    
    ...
    
}

複数の上限境界の例

public class Foo<T1 extends BarClass & IHoge1, T2> {
    
    ...
    
}

クラスBarClassのサブクラスでかつインターフェースIHoge1, IHoge2を実装している型は <T extends BarClass & IHoge1 & IHoge2>& でつないで書く。& で連結する型のうち、クラスは必ず先頭に書く。

Scala

上限境界の例

class Foo[T1 <: Bar, T2] {
    
    ...
    
}

複数の上限境界の例 (いったん複数の上限を1つのクラスで定義してしまう)

class B extends BarClass with IHoge1;

class Foo[T1 <: B, T2] {
    
    ...
    
}

下限境界の例

class Foo[T1 >: Bar, T2] {
    
    ...
    
}
このサイトは筆者(hydrocul)の個人メモの集合です。すべてのページは永遠に未完成です。
スポンサーリンク