Como eu imprimo o tipo de uma variável em Rust?

Eu tenho o seguinte:

let mut my_number = 32.90; 

Como faço para imprimir o tipo de my_number ?

Usando type e type_of não funcionou. Existe outra maneira de imprimir o tipo do número?

Se você deseja apenas descobrir o tipo de variável e está disposto a fazê-lo em tempo de compilation, você pode causar um erro e fazer com que o compilador o capte.

Por exemplo, defina a variável para um tipo que não funciona ( let () = x; também funcionaria):

 error[E0308]: mismatched types --> :2:29 | 2 | let mut my_number: () = 32.90; | ^^^^^ expected (), found floating-point variable | = note: expected type `()` = note: found type `{float}` error: aborting due to previous error 

Ou na maioria dos casos, chame um método inválido ou obtenha um campo inválido :

 error: no method named `what_is_this` found for type `{float}` in the current scope --> :3:15 | 3 | my_number.what_is_this(); | ^^^^^^^^^^^^ error: aborting due to previous error 
 error: attempted access of field `what_is_this` on type `{float}`, but no field with that name was found --> :3:5 | 3 | my_number.what_is_this | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error 

Estes revelam o tipo, que neste caso não está totalmente resolvido. É chamado de “variável de ponto flutuante” no primeiro exemplo e “ {float} ” em todos os três exemplos; este é um tipo parcialmente resolvido que pode acabar em f32 ou f64 , dependendo de como você o usa. ” {float} ” não é um nome de tipo legal, é um espaço reservado que significa “Não tenho certeza absoluta do que é isso”, mas é um número de ponto flutuante. No caso de variables ​​de ponto flutuante, se você não restringir, o padrão será f64 ¹. (Um literal inteiro não qualificado será o padrão para i32 .)


¹ Ainda pode haver maneiras de desconcertar o compilador para que ele não possa decidir entre f32 e f64 ; Não tenho certeza. Costumava ser tão simples quanto 32.90.eq(&32.90) , mas isso trata tanto o f64 agora quanto o chugs alegremente, então eu não sei.

Existe uma function instável std::intrinsics::type_name que pode obter o nome de um tipo, embora você tenha que usar uma compilation noturna de Rust (é improvável que isso funcione em Rust estável). Aqui está um exemplo:

 #![feature(core_intrinsics)] fn print_type_of(_: &T) { println!("{}", unsafe { std::intrinsics::type_name::() }); } fn main() { print_type_of(&32.90); // prints "f64" print_type_of(&vec![1, 2, 4]); // prints "std::vec::Vec" print_type_of(&"foo"); // prints "&str" } 

Se você conhece todos os tipos de antemão, você pode usar características para adicionar um método 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" } } //... 

Não intrínsecos ou nada, então, embora mais limitado, esta é a única solução aqui que você recebe uma seqüência de caracteres e é estável. No entanto, é muito trabalhoso e não conta com parâmetros de tipo, então poderíamos …

 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() } } macro_rules! type_of { ($x:expr) => { (&$x).type_of() }; } 

Vamos usar isso:

 impl_type_info!(i32, i64, f32, f64, str, String, Vec, Result) fn main() { println!("{}", type_of!(1)); println!("{}", type_of!(&1)); println!("{}", type_of!(&&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!("{}", >::type_name()); println!("{}", <&i32>::type_name()); println!("{}", <&str>::type_name()); } 

saída:

 i32 &i32 &&i32 f64 &str &&str String Vec Result &i32 &str 

Parque Infantil Ferrugem

UPD O seguinte não funciona mais. Verifique a resposta de Shubham para correção.

Confira std::intrinsics::get_tydesc() . Está em estado “experimental” agora, mas está tudo bem se você está apenas hackeando o sistema de tipos.

Confira o seguinte exemplo:

 fn print_type_of(_: &T) -> () { let type_name = unsafe { (*std::intrinsics::get_tydesc::()).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" } 

Isto é o que é usado internamente para implementar o famoso formatador {:?} .

Eu montei uma pequena checkbox para fazer isso com base na resposta do vbo. Ele fornece uma macro para retornar ou imprimir o tipo.

Coloque isso no seu arquivo Cargo.toml:

 [dependencies] t_bang = "0.1.2" 

Então você pode usá-lo assim:

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

Você também pode usar a abordagem simples de usar a variável em println!("{:?}", var) . Se Debug não for implementado para o tipo, você poderá ver o tipo na mensagem de erro do compilador:

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

( cercadinho )

Está sujo mas funciona.