我有以下几点:

let mut my_number = 32.90;

如何打印my_number的类型?

使用type和type_of不起作用。有其他方法可以打印数字的类型吗?


当前回答

宏形式允许使用“无处不在”,而函数需要一个对象来解析。

宏表单(一行):

macro_rules! ty {($type:ty) => {std::any::type_name::<$type>()}}

形成的宏观形式:

macro_rules! ty {
    ($type:ty) => {
        std::any::type_name::<$type>()
    };
}

函数形式(借用是为了不破坏已解析的变量):

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

例子:

macro_rules! ty {($type:ty) => {std::any::type_name::<$type>()}}
fn type_of<T>(_: &T) -> &'static str {std::any::type_name::<T>()}

struct DontMater<T>(T);

impl<T: std::fmt::Debug> std::fmt::Debug for DontMater<T> {
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        fmt.write_fmt(format_args!("DontMater<{}>({:?})", ty!(T), self.0))
    }
}

fn main() {
    type µ = [Vec<String>; 7];
    println!("{:?}", DontMater(5_usize));
    println!("{:?}", DontMater("¤"));
    println!("{}", ty!(char));
    println!("{:?}", ty!(µ));
    println!("{}", type_of(&DontMater(72_i8)));
    println!("{:?}", type_of(&15_f64));
}

返回:

DontMater<usize>(5)
DontMater<&str>("¤")
char
"[alloc::vec::Vec<alloc::string::String>; 7]"
env_vars::DontMater<i8>
"f64"

其他回答

如果你事先知道所有的类型,你可以使用trait来添加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"
    }
}

//...

没有复杂或什么都没有,所以尽管有更多的限制,这是唯一的解决方案,让你得到一个字符串,是稳定的。(参见Boiethios的回答)然而,这是非常费力的,并且没有考虑类型参数,所以我们可以……

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

生锈的操场

其他一些答案不工作,但我发现typename crate工作。

Create a new project: cargo new test_typename Modify the Cargo.toml [dependencies] typename = "0.1.1" 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()); }

输出结果为:

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

在稳定rust中有一个@ChrisMorgan答案可以获得近似类型(“float”),在夜间rust中有一个@ShubhamJain答案可以通过不稳定函数获得精确类型(“f64”)。

现在有一种方法可以得到精确的类型(即在f32和f64之间决定)在稳定的rust:

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

略短,但可读性稍差。

您还可以使用println中的变量!("{:?}”,var)。如果没有为该类型实现Debug,则可以在编译器的错误消息中看到该类型:

mod some {
    pub struct SomeType;
}

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

(游戏围栏)

虽然很脏,但很管用。

短篇小说;

fn tyof<T>(_: &T) -> String {
    std::any::type_name::<T>().into()
}

很长的故事;

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

macro_rules! Type {
    ($($ty:ty),*) => {
        $(
            impl Type for $ty {
                fn type_of(&self) -> String {
                    stringify!($ty).into()
                }
            }
        )*
    }
}

#[rustfmt::skip]
Type!(
    u8, i8, u16, i16, u32, i32, i64, u64, i128, String, [()], (), Vec<()>, &u8, &i8, &u16, &i16, &u32, &i32, &i64, &u64, &i128, &str, &[()], &Vec<()>, &() 
    // add any struct, enum or type you want
);

macro_rules! tyof {
    ($var: expr) => {{
        $var.type_of()
    }};
}

fn main() {
    let x = "Hello world!";
    println!("{}", tyof!(x));
    // or
    println!("{}", x.type_of());

    let x = 5;
    println!("{}", tyof!(x));
    // or
    println!("{}", x.type_of());
}