コンテンツにスキップ

ジェネリクス

ジェネリクスは、型を一つに固定せず、型をパラメーターとして受け取れるようにする仕組みです。同じ型や関数を、複数の具体的な型で再利用できます。

たとえば、値を一つ保持する Box を型ごとに別々に定義する代わりに、型パラメーター T を使って次のように宣言できます。

struct Box<T> {
value: T,
}

利用するときに具体的な型を指定します。

let number_box: Box<i32>;
let text_box: Box<string>;

複数の型パラメーターを持つこともできます。

enum Result<T, E> {
Ok(T),
Error(E),
}

関数も型パラメーターを持てます。

function identity<T>(value: T) -> T {
value
}

呼び出すときは型引数を明示できます。

let value = identity<i32>(42);

型引数を省略しても、渡した値などから T を一つに決められる場合は、その型が使われます。型を決められない場合はコンパイルエラーになります。

ジェネリック型に対する implementation では、対象となる型パラメーターを宣言します。

implementation<T> Box<T> {
function get(self) -> T {
self.value
}
}

指定する型引数の数は、宣言された型パラメーターの数と一致しなければなりません。

Box<i32> // Box<T>
Result<i32, string> // Result<T, E>

数が足りない場合や多すぎる場合はコンパイルエラーになります。

Sobakasu のジェネリクスは単相化によってコンパイルされます。単相化とは、実際に使用された型ごとに具体的な版をコンパイル時に作る方法です。

たとえば identity<i32> と identity<string> を使うと、それぞれの型に対応した処理がコンパイル時に用意されます。実行時に型パラメーターを切り替える仕組みではありません。

そのため、最終的に使用する具体的な型は Udon で扱える必要があります。

Unity や VRChat の外部 API にあるジェネリック機能は、Sobakasu で定義したジェネリック型や関数と同じ条件で利用できるとは限りません。利用可否は Udon が公開している API にも依存します。