Rustで値から型情報を文字列として取得する(stable)
やりたいこと
10を渡したら"i32"という文字列が返り
Some(10)を渡したら"Option<i32>"という文字列が知りたい。
やりかた
以下のtype_of()を定義する。
code:rs
fn type_of<T>(_: &T) -> &'static str {
std::any::type_name::<T>()
}
std::any::type_name::<T>()はstableで利用可能。
以下のように使う。
code:rs
println!("{}", type_of(&10));
// => i32
以下はOptionの例。モジュールも含んでいて完全な感じが嬉しい。
code:rs
println!("{}", type_of(&Some(10)));
// => core::option::Option<i32>
以下のように変数も指定できる。
code:rs
let a = Some(10);
println!("{}", type_of(&a));
// => core::option::Option<i32>
以下のようにメソッドチェーンして構造体がどんどん入れ子になるときも詳しく知ることができる。
code:rs
fn doubled(x: &i32) -> i32 { x * 2 }
fn is_even(x: &i32) -> bool { x % 2 == 0 }
let iter0 = vec.iter();
let iter1 = iter0.map(doubled);
let iter2 = iter1.filter(is_even);
println!("{}", type_of(&iter2));
// => core::iter::adapters::Filter<core::iter::adapters::Map<core::slice::Iter<i32>, rust_playground::doubled>, rust_playground::is_even>
(rust_playgroundはCargoのname = に指定している名前。)
関数の戻り値でimpl Traitがうまいこと指定できないときの最終手段として型名をこの方法で得て直接指定してコンパイルを通すなどに使いたい。 おまけ
上記ではtype_of()という自作関数を定義した。Nightly Rustではそれと同等のことをするstd::any::type_name_of_val()が定義されている。 以下のTracking issueを見るととtype_name_of_valは冗長だからtype_name_ofが良いかもしれない的なことが書かれている。
モジュール名含んだ状態で型が取得できたのは良かった。ただしそのままRustとして出力された型を貼り付けても、コンパイルエラーすることがある。非公開になっている型などになっている影響。どこかでtypeで型エイリアスになった公開された型をうまく見つける必要がある。
HaskellのGHCIの:tみたいなことがしたかった。:tが型クラスを教えてくれるようにRustで型だけではなくトレイトも教えてくれる方法があると捗りそう。