ジェネリクス

ジェネリクスとは、型と関数の機能をより汎用的に使えるようにするための機能です。これはあらゆる局面でコードの重複を避けるために非常に役立ちますが、多少構文が複雑になります。すなわち、ジェネリック型を使いこなすには、どのようなジェネリック型がきちんと機能するかに細心の注意を払う必要があります。 最もシンプルで一般的なジェネリクスの利用法は型パラメータです。

ジェネリック型の型パラメータにはかぎ括弧(angle brackets)とアッパーキャメルケース(camel case)が使われます。: <Aaa, Bbb, ...>ジェネリックな型パラメータはたいていの場合<T>で示されます。Rustの場合、「ジェネリクス」には「1つ以上のジェネリックな型パラメータ<T>を受け付けるもの」という意味もあります。ジェネリックな型パラメータを指定された場合、それは必ずジェネリック型になり、そうでなければ必ず非ジェネリック型、すなわち具象型(concrete)になります。

例として、あらゆる型の引数Tをとる ジェネリック関数 fooを定義すると:

fn foo<T>(arg: T) { ... }

となります。Tはジェネリックな型パラメータに指定されているので、この場所で(arg: T)のように使用するとジェネリック型として扱われます。これはTという構造体がそれ以前に定義されていても同様です。

では、手を動かしながらジェネリック型の構文を体験していきましょう。

// A concrete type `A`.
// `A`という具象型
struct A;

// In defining the type `Single`, the first use of `A` is not preceded by `<A>`.
// Therefore, `Single` is a concrete type, and `A` is defined as above.
// `Single`という型を定義する際に`A`を使用しているが、その最初の使用よりも
// 先に`<A>`がないため、また、`A`自身も具象型であるため、`Single`は具象型となる。
struct Single(A);
//            ^ Here is `Single`s first use of the type `A`.
//            ^ Singleによる`A`の一番最初の使用はここ

// Here, `<T>` precedes the first use of `T`, so `SingleGen` is a generic type.
// Because the type parameter `T` is generic, it could be anything, including
// the concrete type `A` defined at the top.
// ここでは`<T>`が一番初めの`T`の使用よりも先に来ている。よって`SingleGen`はジェネリック型
// となる。なぜならば型パラメータ`T`がジェネリックだからである。`T`はどんな型にもなりえるため、
// 上で定義した`A`を受け取ることもできる。
struct SingleGen<T>(T);

fn main() {
    // `Single` is concrete and explicitly takes `A`.
    // `Single`は具象型で、`A`のみを受け取る。
    let _s = Single(A);
    
    // Create a variable `_char` of type `SingleGen<char>`
    // and give it the value `SingleGen('a')`.
    // Here, `SingleGen` has a type parameter explicitly specified.
    // `_char`という名の変数を生成する。これは`SingleGen<char>`
    // という型で、値は`SingleGen('a')`となる。ここでは、`SingleGen`には明示的な型パラメータ
    // が与えられている。
    let _char: SingleGen<char> = SingleGen('a');

    // `SingleGen` can also have a type parameter implicitly specified:
    // `SingleGen`型の変数には明示的に型パラメータを与えなくてもよい。
    let _t    = SingleGen(A); // Uses `A` defined at the top.
                              // 上で定義した`A`を使用
    let _i32  = SingleGen(6); // Uses `i32`.
                              // `i32`を使用
    let _char = SingleGen('a'); // Uses `char`.
                                // `char`を使用
}

参照

構造体