English

Generics

関数の Generics

関数名の直後に <T> を記述することで、型パラメータを定義できます。

fn func<T>( val:T ): List<T> {
    return [ val ];
}
let l1 = func( 10 ); // List
let l2 = func( "abc" ); // List
呼び出し時の型推論が効くため、func<int>(10) のように明示する必要は通常ありません。

クラスの Generics

クラス名の直後に <T> を記述します。

class Box<T> {
    let val:T;
    pub fn __init( val:T ) { self.val = val; }
    pub fn get(): T { return self.val; }
}
let b = new Box( 100 ); // Box

※ インタフェースは Generics をサポートしていません。

型パラメータの制約

<T:Constraint> の形式で、型パラメータが特定のクラスを継承、またはインタフェースを実装していることを強制できます。

interface Val {
    pub fn getValue(): int;
}
fn printVal<T:(Val)>( obj:T ) {
    print( obj.getValue() ); // T は Val を実装しているので呼び出し可能
}

Mapping 可能な Generics クラスを作る場合にも制約が必須となります。

class Model<T:(Mapping)> extend (Mapping) {
    let data:T;
}

上記の T:(Mapping) がないと、Mapping インタフェースの実装要件 (全メンバが Mapping 可能であること) を満たせない可能性があるためコンパイルエラーとなります。

メソッドの Generics

クラスのメソッド個別に型パラメータを持たせることも可能です。

class Test {
    pub fn convert<T>( val:T ): str {
        return "val: %s" (val);
    }
}

Generics と Mutability

型パラメータ T は、宣言時に修飾することで Mutability や Nilability を制御できます。

fn func<T>( val:T ): &T { return val; } // Immutable な T を返す
fn func2<T>( val:T! ): T { return unwrap val; } // Nilable な引数を受け取り、Non-nil を返す
<T!> のように、型パラメータの定義自体に ! を付けることはできません。
func<T>( val:T! ) のように使用箇所で指定します。