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

2020-01-22 12:23发布

I have the following:

let mut my_number = 32.90;

How do I print the type of my_number?

Using type and type_of did not work. Is there another way I can print the number's type?

标签: types rust
10条回答
乱世女痞
2楼-- · 2020-01-22 12:37

You can use the std::any::type_name function. This doesn't need a nightly compiler or an external crate, and the results are quite correct:

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

Be warned: as said in the documentation, this information must be used for a debug purpose only:

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

If you want your type representation to stay the same between compiler versions, you should use a trait, like in the phicr's answer.

查看更多
Lonely孤独者°
3楼-- · 2020-01-22 12:38

If you merely wish to find out the type of a variable and are willing to do it at compile time, you can cause an error and get the compiler to pick it up.

For example, set the variable to a type which doesn't work:

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

Or call an invalid method:

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

Or access an invalid field:

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

See also:


¹ There may still be ways of baffling the compiler so that it can’t decide between f32 and f64; I’m not sure. It used to be as simple as 32.90.eq(&32.90), but that treats both as f64 now and chugs along happily, so I don’t know.

查看更多
We Are One
4楼-- · 2020-01-22 12:39

I put together a little crate to do this based off vbo's answer. It gives you a macro to return or print out the type.

Put this in your Cargo.toml file:

[dependencies]
t_bang = "0.1.2"

Then you can use it like so:

#[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"
}
查看更多
再贱就再见
5楼-- · 2020-01-22 12:41

There is an unstable function std::intrinsics::type_name that can get you the name of a type, though you have to use a nightly build of Rust (this is unlikely to ever work in stable Rust). Here’s an example:

#![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"
}
查看更多
forever°为你锁心
6楼-- · 2020-01-22 12:43

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.

查看更多
冷血范
7楼-- · 2020-01-22 12:48

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.

查看更多
登录 后发表回答