rs.nkmk.me

Rustで変数の型の名前を取得・確認

Posted: | Tags: Rust

Rustで変数の型の名前を文字列で取得し確認するにはstd::any::type_nameを利用する。

なお、Rustは静的型付き言語であり、例えばVSCode + rust-analyzerではソースコード上の変数にマウスを合わせるとその型が確認できる。std::any::type_nameのドキュメントにあるように、コード内で型の名前を取得するのはあくまでも診断・デバッグのため。

This is intended for diagnostic use. The exact contents and format of the string returned are not specified, other than being a best-effort description of the type. type_name in std::any - Rust

型の名前を文字列スライスで取得: std::any::type_name

std::any::type_nameは型の名前を文字列スライスで返す。

ターボフィッシュ::<>で型を指定する。ここでは便宜上assert_eq!を使っているが、結果を出力したい場合はprintln!などを使えばよい。以降も同様。

assert_eq!(std::any::type_name::<i32>(), "i32");
assert_eq!(std::any::type_name::<bool>(), "bool");
source: type_of.rs

ドキュメントにあるように、返される文字列はユニークであるとは限らず、コンパイラのバージョンによって出力が変わる可能性もある。例えばrustc 1.67.0時点ではライフタイム注釈は無視される。

assert_eq!(std::any::type_name::<&str>(), "&str");
assert_eq!(std::any::type_name::<&'static str>(), "&str");
source: type_of.rs

以降の例もすべてrustc 1.67.0のもの。

プリミティブ型以外はモジュールを含む名前が返される。stdではなくalloccoreが使われる。

assert_eq!(std::any::type_name::<String>(), "alloc::string::String");
assert_eq!(std::any::type_name::<Vec<i32>>(), "alloc::vec::Vec<i32>");
assert_eq!(
    std::any::type_name::<Option<i32>>(),
    "core::option::Option<i32>"
);
source: type_of.rs

入れ子になっている場合。

assert_eq!(
    std::any::type_name::<Vec<String>>(),
    "alloc::vec::Vec<alloc::string::String>"
);
assert_eq!(
    std::any::type_name::<Option<String>>(),
    "core::option::Option<alloc::string::String>"
);
source: type_of.rs

自分で定義した構造体の場合。例のtype_ofはファイル名(type_of.rs)。Cargo.toml[package][[bin]]nameを指定している場合はそれが使われる。

struct MyStruct(i32);
assert_eq!(std::any::type_name::<MyStruct>(), "type_of::main::MyStruct");
source: type_of.rs

typeで型エイリアスを定義した場合、元の型の名前が返される。

type MyAlias = u8;
assert_eq!(std::any::type_name::<MyAlias>(), "u8");
source: type_of.rs

変数の型の名前を文字列スライスで取得

std::any::type_name_of_valは変数の型の名前を文字列スライスで返す。rustc 1.67.0時点はNightly版のみ。

std::any::type_name_of_valの実装を参考に関数を定義する。

fn type_of<T>(_: &T) -> &'static str {
    std::any::type_name::<T>()
}
source: type_of.rs

以下のように使える。

let i = 100;
assert_eq!(type_of(&i), "i32");

let u = 100_u8;
assert_eq!(type_of(&u), "u8");

let b = true;
assert_eq!(type_of(&b), "bool");

let s = "abc";
assert_eq!(type_of(&s), "&str");

let t = (100, 100);
assert_eq!(type_of(&t), "(i32, i32)");

let v = vec![String::from("abc")];
assert_eq!(type_of(&v), "alloc::vec::Vec<alloc::string::String>");
source: type_of.rs

参照の場合。

let i = 100;
let ref_i = &i;
assert_eq!(type_of(&ref_i), "&i32");

let mut i = 100;
let mut_ref_i = &mut i;
assert_eq!(type_of(&mut_ref_i), "&mut i32");
source: type_of.rs

配列とスライスの場合。

let a = [0, 1, 2];
assert_eq!(type_of(&a), "[i32; 3]");

let s = &a[1..];
assert_eq!(type_of(&s), "&[i32]");
source: type_of.rs

上で定義した構造体やtypeによる型エイリアスの場合。

let my_struct = MyStruct(100);
assert_eq!(type_of(&my_struct), "type_of::main::MyStruct");

let u: MyAlias = 100;
assert_eq!(type_of(&u), "u8");
source: type_of.rs

より複雑な例。

let it = [0, 1, 2].iter().enumerate();
assert_eq!(
    type_of(&it),
    "core::iter::adapters::enumerate::Enumerate<core::slice::iter::Iter<i32>>"
);

let result = "100".parse::<i32>();
assert_eq!(
    type_of(&result),
    "core::result::Result<i32, core::num::error::ParseIntError>"
);
source: type_of.rs

関連カテゴリー