How do I print the type of a variable in Rust?

后端 未结 11 2132
无人共我
无人共我 2020-11-22 08:49

I have the following:

let mut my_number = 32.90;

How do I print the type of my_number?

Using type and

相关标签:
11条回答
  • 2020-11-22 09:02

    UPD The following does not work anymore. Check Shubham's answer for correction.

    Check out std::intrinsics::get_tydesc<T>(). It is in "experimental" state right now, but it's OK if you are just hacking around the type system.

    Check out the following example:

    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>"
    }
    

    This is what is used internally to implement the famous {:?} formatter.

    0 讨论(0)
  • 2020-11-22 09:05

    You can use std::any::type_name. The following are examples of primitive data types which are capiable without &.

    use std::any::type_name;
    
    fn type_of<T>(_: T) -> &'static str {
        type_name::<T>()
    }
    
    fn main() {
        let str1 = "Rust language";
        let str2 = str1;
        println!("str1 is:  {}, and the type is {}.", str1, type_of(str1));
        println!("str2 is: {}, and the type is {}.", str2, type_of(str2));
        let bool1 = true;
        let bool2 = bool1;
        println!("bool1 is {}, and the type is {}.", bool1, type_of(bool1));
        println!("bool2 is {}, and the type is {}.", bool2, type_of(bool2));
        let x1 = 5;
        let x2 = x1;
        println!("x1 is {}, and the type is {}.", x1, type_of(x1));
        println!("x2 is {}, and the type is {}.", x2, type_of(x2));
        let a1 = 'a';
        let a2 = a1;
        println!("a1 is {}, and the type is {}.", a1, type_of(a1));
        println!("a2 is {}, and the type is {}.", a2, type_of(a2));
        let tup1= ("hello", 5, 'c');
        let tup2 = tup1;
        println!("tup1 is {:?}, and the type is {}.", tup1, type_of(tup1));
        println!("tup2 is {:?}, and the type is {}.", tup2, type_of(tup2));
        let array1: [i32; 3] = [0; 3];
        let array2 = array1;
        println!("array1 is {:?}, and the type is {}.", array1, type_of(array1));
        println!("array2 is {:?}, and the type is {}.", array2, type_of(array2));
        let array: [i32; 5] = [0, 1, 2, 3, 4];
        let slice1 = &array[0..3];
        let slice2 = slice1;
        println!("slice1 is {:?}, and the type is {}.", slice1, type_of(slice1));
        println!("slice2 is {:?}, and the type is {}.", slice2, type_of(slice2));
    }
    

    The output is

    str1 is:  Rust language, and the type is &str.
    str2 is: Rust language, and the type is &str.
    bool1 is true, and the type is bool.
    bool2 is true, and the type is bool.
    x1 is 5, and the type is i32.
    x2 is 5, and the type is i32.
    a1 is a, and the type is char.
    a2 is a, and the type is char.
    tup1 is ("hello", 5, 'c'), and the type is (&str, i32, char).
    tup2 is ("hello", 5, 'c'), and the type is (&str, i32, char).
    array1 is [0, 0, 0], and the type is [i32; 3].
    array2 is [0, 0, 0], and the type is [i32; 3].
    slice1 is [0, 1, 2], and the type is &[i32].
    slice2 is [0, 1, 2], and the type is &[i32].
    
    0 讨论(0)
  • 2020-11-22 09:06

    Some other answers don't work, but I find that the typename crate works.

    1. Create a new project:

      cargo new test_typename
      
    2. Modify the Cargo.toml

      [dependencies]
      typename = "0.1.1"
      
    3. Modify your source code

      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());
      }
      

    The output is:

    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
    
    0 讨论(0)
  • 2020-11-22 09:07

    If your just wanting to know the type of your variable during interactive development, I would highly recommend using rls (rust language server) inside of your editor or ide. You can then simply permanently enable or toggle the hover ability and just put your cursor over the variable. A little dialog should come up with information about the variable including the type.

    0 讨论(0)
  • 2020-11-22 09:12

    If you know all the types beforehand, you can use traits to add a type_of method:

    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"
        }
    }
    
    //...
    

    No intrisics or nothin', so although more limited this is the only solution here that gets you a string and is stable. (see French Boiethios's answer) However, it's very laborious and doesn't account for type parameters, so we could...

    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() };
    }
    

    Let's use it:

    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());
    }
    

    output:

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

    Rust Playground

    0 讨论(0)
  • 2020-11-22 09:12

    There's a @ChrisMorgan answer to get approximate type ("float") in stable rust and there's a @ShubhamJain answer to get precise type ("f64") through unstable function in nightly rust.

    Now here's a way one can get precise type (ie decide between f32 and f64) in stable rust:

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

    results in

    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)
    

    Update

    The turbofish variation

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

    is slightly shorter but somewhat less readable.

    0 讨论(0)
提交回复
热议问题