web-dev-qa-db-ja.com

Rustで変数の型を印刷するにはどうすればよいですか?

私は次のものを持っています:

let mut my_number = 32.90;

my_numberのタイプを印刷するにはどうすればよいですか?

typeおよびtype_ofの使用は機能しませんでした。番号のタイプを印刷できる別の方法はありますか?

177
user2431012

変数の型を見つけ出しし、コンパイル時に実行したいだけの場合は、エラーを発生させ、コンパイラをそれを拾います。

たとえば、 変数を動作しない型に設定しますlet () = x;も動作します):

error[E0308]: mismatched types
 --> <anon>:2:29
  |
2 |     let mut my_number: () = 32.90;
  |                             ^^^^^ expected (), found floating-point variable
  |
  = note: expected type `()`
  = note:    found type `{float}`

error: aborting due to previous error

またはほとんどの場合 無効なメソッドを呼び出す または 無効なフィールドを取得する

error: no method named `what_is_this` found for type `{float}` in the current scope
 --> <anon>:3:15
  |
3 |     my_number.what_is_this();
  |               ^^^^^^^^^^^^

error: aborting due to previous error
error: attempted access of field `what_is_this` on type `{float}`, but no field with that name was found
 --> <anon>:3:5
  |
3 |     my_number.what_is_this
  |     ^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

これらはタイプを明らかにします。この場合、実際には完全には解決されません。最初の例では「浮動小数点変数」、3つすべての例では「{float}」と呼ばれます。これは部分的に解決された型であり、使用方法に応じてf32またはf64になります。 「{float}」は正当なタイプ名ではなく、「これが何であるか完全にはわからない」という意味のプレースホルダーですが、isフローティング-ポイント番号。浮動小数点変数の場合、制約を付けないと、デフォルトでf64¹になります。 (非修飾整数リテラルは、デフォルトでi32になります。)


¹f32f64の間で判断できないように、コンパイラを困惑させる方法がまだあるかもしれません。よく分かりません。以前は32.90.eq(&32.90)のように単純でしたが、現在はf64として扱われ、喜んで一緒に動きますので、わかりません。

140
Chris Morgan

Rustの夜間ビルドを使用する必要がありますが、不安定な関数 std::intrinsics::type_name があります。 。 例は次のとおりです

#![feature(core_intrinsics)]

fn print_type_of<T>(_: &T) {
    println!("{}", unsafe { std::intrinsics::type_name::<T>() });
}

fn main() {
    print_type_of(&32.90);          // prints "f64"
    print_type_of(&vec![1, 2, 4]);  // prints "std::vec::Vec<i32>"
    print_type_of(&"foo");          // prints "&str"
}
87
Shubham Jain

すべての型を事前に知っている場合は、特性を使用してtype_ofメソッドを追加できます。

trait TypeInfo {
    fn type_of(&self) -> &'static str;
}

impl TypeInfo for i32 {
    fn type_of(&self) -> &'static str {
        "i32"
    }
}

impl TypeInfo for i64 {
    fn type_of(&self) -> &'static str {
        "i64"
    }
}

//...

組み込み関数やnothin 'はありません。したがって、より制限されていますが、これが文字列を取得して安定する唯一のソリューションです。ただし、非常に面倒であり、型パラメーターを考慮しないため、...

trait TypeInfo {
    fn type_name() -> String;
    fn type_of(&self) -> String;
}

macro_rules! impl_type_info {
    ($($name:ident$(<$($T:ident),+>)*),*) => {
        $(impl_type_info_single!($name$(<$($T),*>)*);)*
    };
}

macro_rules! mut_if {
    ($name:ident = $value:expr, $($any:expr)+) => (let mut $name = $value;);
    ($name:ident = $value:expr,) => (let $name = $value;);
}

macro_rules! impl_type_info_single {
    ($name:ident$(<$($T:ident),+>)*) => {
        impl$(<$($T: TypeInfo),*>)* TypeInfo for $name$(<$($T),*>)* {
            fn type_name() -> String {
                mut_if!(res = String::from(stringify!($name)), $($($T)*)*);
                $(
                    res.Push('<');
                    $(
                        res.Push_str(&$T::type_name());
                        res.Push(',');
                    )*
                    res.pop();
                    res.Push('>');
                )*
                res
            }
            fn type_of(&self) -> String {
                $name$(::<$($T),*>)*::type_name()
            }
        }
    }
}

impl<'a, T: TypeInfo + ?Sized> TypeInfo for &'a T {
    fn type_name() -> String {
        let mut res = String::from("&");
        res.Push_str(&T::type_name());
        res
    }
    fn type_of(&self) -> String {
        <&T>::type_name()
    }
}

impl<'a, T: TypeInfo + ?Sized> TypeInfo for &'a mut T {
    fn type_name() -> String {
        let mut res = String::from("&mut ");
        res.Push_str(&T::type_name());
        res
    }
    fn type_of(&self) -> String {
        <&mut T>::type_name()
    }
}

macro_rules! type_of {
    ($x:expr) => { (&$x).type_of() };
}

それを使用しましょう:

impl_type_info!(i32, i64, f32, f64, str, String, Vec<T>, Result<T,S>)

fn main() {
    println!("{}", type_of!(1));
    println!("{}", type_of!(&1));
    println!("{}", type_of!(&&1));
    println!("{}", type_of!(&mut 1));
    println!("{}", type_of!(&&mut 1));
    println!("{}", type_of!(&mut &1));
    println!("{}", type_of!(1.0));
    println!("{}", type_of!("abc"));
    println!("{}", type_of!(&"abc"));
    println!("{}", type_of!(String::from("abc")));
    println!("{}", type_of!(vec![1,2,3]));

    println!("{}", <Result<String,i64>>::type_name());
    println!("{}", <&i32>::type_name());
    println!("{}", <&str>::type_name());
}

出力:

i32
&i32
&&i32
&mut i32
&&mut i32
&mut &i32
f64
&str
&&str
String
Vec<i32>
Result<String,i64>
&i32
&str

錆遊び場

45
phicr

UPD以下はもう機能しません。 Shubham's answer をチェックして修正します。

std::intrinsics::get_tydesc<T>()を確認してください。現在は「実験的」な状態ですが、型システムをハックしているだけなら問題ありません。

次の例をご覧ください。

fn print_type_of<T>(_: &T) -> () {
    let type_name =
        unsafe {
            (*std::intrinsics::get_tydesc::<T>()).name
        };
    println!("{}", type_name);
}

fn main() -> () {
    let mut my_number = 32.90;
    print_type_of(&my_number);       // prints "f64"
    print_type_of(&(vec!(1, 2, 4))); // prints "collections::vec::Vec<int>"
}

これは、有名な{:?}フォーマッタを実装するための 内部で使用 です。

18
vbo

私は、vboの答えに基づいてこれを行うために、小さな箱をまとめました。型を返すか印刷するマクロを提供します。

これをCargo.tomlファイルに入れます:

[dependencies]
t_bang = "0.1.2"

その後、次のように使用できます。

#[macro_use] extern crate t_bang;
use t_bang::*;

fn main() {
  let x = 5;
  let x_type = t!(x);
  println!("{:?}", x_type);  // prints out: "i32"
  pt!(x);                    // prints out: "i32"
  pt!(5);                    // prints out: "i32"
}
11
mpiccolo

println!("{:?}", var)の変数を使用する簡単なアプローチも使用できます。タイプにDebugが実装されていない場合、コンパイラのエラーメッセージでタイプを確認できます。

mod some {
    pub struct SomeType;
}

fn main() {
    let unknown_var = some::SomeType;
    println!("{:?}", unknown_var);
}

playpen

汚れていますが、動作します。

6
DenisKolodin

安定したRustに近似タイプ( "float")を取得する@ChrisMorgan answer と@ShubhamJain answer 夜間のRustの不安定な機能を通じて正確な型( "f64")を取得します。

ここで、安定したRustで正確な型を取得する(つまり、f32とf64の間で決定する)方法を示します。

fn main() {
    let a = 5.;
    let _: () = unsafe { std::mem::transmute(a) };
}

結果として

error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
 --> main.rs:3:27
  |
3 |     let _: () = unsafe { std::mem::transmute(a) };
  |                           ^^^^^^^^^^^^^^^^^^^
  |
  = note: source type: `f64` (64 bits)
  = note: target type: `()` (0 bits)

更新

ターボフィッシュバリエーション

fn main() {
    let a = 5.;
    unsafe { std::mem::transmute::<_, ()>(a) }
}

少し短くなりますが、多少読みにくくなります。

2

他のいくつかの答えは機能しませんが、 typename crateは機能することがわかります。

  1. 新しいプロジェクトを作成します。

    cargo new test_typename
    
  2. Cargo.tomlを変更します

    [dependencies]
    typename = "0.1.1"
    
  3. ソースコードを変更する

    use typename::TypeName;
    
    fn main() {
        assert_eq!(String::type_name(), "std::string::String");
        assert_eq!(Vec::<i32>::type_name(), "std::vec::Vec<i32>");
        assert_eq!([0, 1, 2].type_name_of(), "[i32; 3]");
    
        let a = 65u8;
        let b = b'A';
        let c = 65;
        let d = 65i8;
        let e = 65i32;
        let f = 65u32;
    
        let arr = [1,2,3,4,5];
        let first = arr[0];
    
        println!("type of a 65u8  {} is {}", a, a.type_name_of());
        println!("type of b b'A'  {} is {}", b, b.type_name_of());
        println!("type of c 65    {} is {}", c, c.type_name_of());
        println!("type of d 65i8  {} is {}", d, d.type_name_of());
        println!("type of e 65i32 {} is {}", e, e.type_name_of());
        println!("type of f 65u32 {} is {}", f, f.type_name_of());
    
        println!("type of arr {:?} is {}", arr, arr.type_name_of());
        println!("type of first {} is {}", first, first.type_name_of());
    }
    

出力は次のとおりです。

type of a 65u8  65 is u8
type of b b'A'  65 is u8
type of c 65    65 is i32
type of d 65i8  65 is i8
type of e 65i32 65 is i32
type of f 65u32 65 is u32
type of arr [1, 2, 3, 4, 5] is [i32; 5]
type of first 1 is i32
1
Flyq