
前回はユニット様構造体というメンバ無、大きさゼロの構造体を見ました。でもこれ、れっきとした「具象型」でした。空だけれども型はあるのだと。今回は「なんにでもなる」ジェネリクス型の構造体を作って触ってみます。「なんにでもなる」ということは、実体が空のユニット様構造体を型パラメータにしても良いのだと。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が入ります。
エラーなく動作はしたけれども、分かったような、分からぬような。
