我有以下几点:

let mut my_number = 32.90;

如何打印my_number的类型?

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


当前回答

1.38版新增std::any::type_name

use std::any::type_name;

fn type_of<T>(_: T) -> &'static str {
    type_name::<T>()
}
fn main() {
    let x = 21;
    let y = 2.5;
    println!("{}", type_of(&y));
    println!("{}", type_of(x));
}

其他回答

**更新**最近没有被验证工作。

我把一个小板条箱一起做这个基于vbo的答案。它提供了一个宏来返回或打印类型。

把这个放在你的货物里。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"
}

如果你只是想找出一个变量的类型,并愿意在编译时执行,你可能会导致一个错误,并让编译器拾取它。

例如,将变量设置为一个无效的类型:

let mut my_number: () = 32.90;
// let () = x; would work too
error[E0308]: mismatched types
 --> src/main.rs:2:29
  |
2 |     let mut my_number: () = 32.90;
  |                             ^^^^^ expected (), found floating-point number
  |
  = note: expected type `()`
             found type `{float}`

或者调用无效的方法:

let mut my_number = 32.90;
my_number.what_is_this();
error[E0599]: no method named `what_is_this` found for type `{float}` in the current scope
 --> src/main.rs:3:15
  |
3 |     my_number.what_is_this();
  |               ^^^^^^^^^^^^

或访问无效字段:

let mut my_number = 32.90;
my_number.what_is_this
error[E0610]: `{float}` is a primitive type and therefore doesn't have fields
 --> src/main.rs:3:15
  |
3 |     my_number.what_is_this
  |               ^^^^^^^^^^^^

These reveal the type, which in this case is actually not fully resolved. It’s called “floating-point variable” in the first example, and “{float}” in all three examples; this is a partially resolved type which could end up f32 or f64, depending on how you use it. “{float}” is not a legal type name, it’s a placeholder meaning “I’m not completely sure what this is”, but it is a floating-point number. In the case of floating-point variables, if you don't constrain it, it will default to f64¹. (An unqualified integer literal will default to i32.)

参见:

编译器错误消息中的{integer}或{float}是什么?


¹可能仍然有一些让编译器困惑的方法,使它无法在f32和f64之间做出决定;我不确定。它曾经像32.90.eq(&32.90)一样简单,但现在两者都被视为f64,并且可以愉快地进行,所以我不知道。

这是@Boiethios回答的简化版。我已经从原始解决方案中删除了一些“&”符号。

fn print_type_of<T>(_: T) {
    println!("{}", std::any::type_name::<T>())
}

fn main() {
    let s = "Hello";
    let i = 42;

    print_type_of(s); // &str
    print_type_of(i); // i32
    print_type_of(main); // playground::main
    print_type_of(print_type_of::<i32>); // playground::print_type_of<i32>
    print_type_of(|| "Hi!" ); // playground::main::{{closure}}
}

Rust游乐场的景观

在稳定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) }
}

略短,但可读性稍差。

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

生锈的操场