前回はユニット様構造体というメンバ無、大きさゼロの構造体を見ました。でもこれ、れっきとした「具象型」でした。空だけれども型はあるのだと。今回は「なんにでもなる」ジェネリクス型の構造体を作って触ってみます。「なんにでもなる」ということは、実体が空のユニット様構造体を型パラメータにしても良いのだと。Rustは禅問答?喝!
※「やっつけな日常」投稿順 indexはこちら
いつもお世話になっております「Rust By Example 日本語版」の以下のページを参照させていただいております。
上記から1か所引用させていただきます。
ジェネリックな型パラメータを指定された場合、それは必ずジェネリック型になり、そうでなければ必ず非ジェネリック型、すなわち具象型(concrete)になります。
そういわれてもな~。実際にやってみないと身に染みませぬ。上記ページの例題をベースに勝手に拡張、動かして体感してみましたです。
実験に使用したソース
最初はいくつか構造体を定義してみました。まず、先週もやったユニット様構造体です。
struct U;
構造体のフィールドなどないのだけれど、立派な構造体であり、型だと。
その型Uを要素に持つ、タプル型構造体を定義してみます。こんな感じ。
struct B(U);
タプルというからには要素が複数になっても良いのだよね、ということでこんな感じ。
struct C(U, U);
空のUが2個も並んで何じゃらほい状態です。さらに今回は、ジェネリクス型の構造体も定義。
struct BGen<T>(T);
鍵カッコの型パラメータを与えると、その型の要素を1個もつタプルを生成するようなジェネリクス型です。
以下のコードでは、上記を使って変数を定義し、その変数や変数のメンバ、変数の型などをprintln!マクロの{:?}フォーマットで印字させてみました。
#[derive(Debug)] struct U; #[derive(Debug)] struct B(U); #[derive(Debug)] struct C(U, U); #[derive(Debug)] struct BGen<T>(T); fn type_of<T>(_: T) -> String{ let a = std::any::type_name::<T>(); return a.to_string(); } fn main() { let u = U; let b = B(U); let c = C(U, U); let b_char: BGen<char> = BGen('a'); let b_u = BGen(U); let b_i32 = BGen(6); let b_char2 = BGen('d'); println!("u = {:?}", u); println!("b = {:?}", b); println!("b.0 = {:?}", b.0); println!("c = {:?}", c); println!("c.0 = {:?}", c.0); println!("c.0 = {:?}", c.1); println!("b_char = {:?}", b_char); println!("b_char.0 = {:?}", b_char.0); println!("b_u = {:?}", b_u); println!("b_u.0 = {:?}", b_u.0); println!("b_i32 = {:?}", b_i32); println!("b_i32.0 = {:?}", b_i32.0); println!("b_char2 = {:?}", b_char2); println!("b_char2.0 = {:?}", b_char2.0); println!("type(b_u) = {:?}", type_of(&b_u)); println!("type(b_i32) = {:?}", type_of(&b_i32)); println!("type(b_char) = {:?}", type_of(&b_char)); println!("type(b_char2)= {:?}", type_of(&b_char2)); }
実験結果
まずメンバを持たないユニット様構造体Uですが、立派に具象型として振舞っていることが分かります。中身にフィールドが無いと言わなければフツーの変数。
さて、ジェネリクス型は与えた型により、ジェネリクスの鍵カッコの中が切り替わっているのが分かります。UをあたえればU、整数を与えればi32、文字を与えればcharが入ります。
エラーなく動作はしたけれども、分かったような、分からぬような。