I have the following:
let mut my_number = 32.90;
How do I print the type of my_number
?
Using type
and
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.
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].
Some other answers don't work, but I find that the typename crate works.
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());
}
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
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.
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
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.