Tengo lo siguiente:
let mut my_number = 32.90;
¿Cómo imprimo el tipo de my_number
?
Usando type
y type_of
no funcionó. ¿Hay alguna otra forma en que pueda imprimir el tipo de número?
Tengo lo siguiente:
let mut my_number = 32.90;
¿Cómo imprimo el tipo de my_number
?
Usando type
y type_of
no funcionó. ¿Hay alguna otra forma en que pueda imprimir el tipo de número?
Respuestas:
Si simplemente desea averiguar el tipo de una variable y está dispuesto a hacerlo en el momento de la compilación, puede causar un error y hacer que el compilador lo recoja.
Por ejemplo, establezca la variable en un tipo que no funciona :
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}`
O llame a un método no válido :
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();
| ^^^^^^^^^^^^
O acceda a un campo no válido :
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
| ^^^^^^^^^^^^
Estos revelan el tipo, que en este caso en realidad no está completamente resuelto. Se llama "variable de punto flotante" en el primer ejemplo y " {float}
" en los tres ejemplos; Este es un tipo parcialmente resuelto que podría terminar f32
o f64
, dependiendo de cómo lo use. " {float}
" No es un nombre de tipo legal, es un marcador de posición que significa "No estoy completamente seguro de qué es", pero es un número de coma flotante. En el caso de las variables de punto flotante, si no lo restringe, el valor predeterminado será f64
¹. (Un literal entero no calificado estará predeterminado en i32
).
Ver también:
¹ Todavía puede haber formas de desconcertar al compilador para que no pueda decidir entre f32
y f64
; No estoy seguro. Solía ser tan simple como 32.90.eq(&32.90)
eso, pero eso trata tanto como f64
ahora y suena feliz, así que no lo sé.
ImageBuffer<_, Vec<_>>
que no me ayuda mucho cuando estoy tratando de escribir una función que tome una de estas cosas como parámetro. Y esto sucede en el código que de lo contrario se compila hasta que agregue el :()
. ¿No hay mejor manera?
Hay una función inestable std::intrinsics::type_name
que puede obtener el nombre de un tipo, aunque debe usar una compilación nocturna de Rust (es poco probable que funcione en Rust estable). Aquí hay un ejemplo:
#![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"
}
#![feature(core_intrinsics)]
print_type_of
está tomando referencias ( &T
), no valores ( T
), por lo que debe pasar en &&str
lugar de &str
; es decir, en print_type_of(&"foo")
lugar de print_type_of("foo")
.
std::any::type_name
es estable desde el óxido 1.38: stackoverflow.com/a/58119924
Puedes usar la std::any::type_name
función. Esto no necesita un compilador nocturno o una caja externa, y los resultados son bastante correctos:
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}}
}
Tenga cuidado: como se dice en la documentación, esta información debe usarse solo para fines de depuración:
Esto está destinado para uso diagnóstico. El contenido exacto y el formato de la cadena no se especifican, aparte de ser una descripción del mejor esfuerzo del tipo.
Si desea que su representación de tipo permanezca igual entre las versiones del compilador, debe usar un rasgo, como en la respuesta del phicr .
Si conoce todos los tipos de antemano, puede usar rasgos para agregar un type_of
método:
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"
}
}
//...
Sin intrínsecos ni nada, por lo que, aunque más limitada, esta es la única solución aquí que te da una cadena y es estable. (vea la respuesta de French Boiethios ) Sin embargo, es muy laborioso y no tiene en cuenta los parámetros de tipo, por lo que podrí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()
}
}
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() };
}
Vamos a usarlo:
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());
}
salida:
i32
&i32
&&i32
&mut i32
&&mut i32
&mut &i32
f64
&str
&&str
String
Vec<i32>
Result<String,i64>
&i32
&str
UPD Lo siguiente ya no funciona. Verifique la respuesta de Shubham para su corrección.
Echa un vistazo std::intrinsics::get_tydesc<T>()
. Está en estado "experimental" en este momento, pero está bien si solo está pirateando el sistema de tipos.
Mira el siguiente ejemplo:
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>"
}
Esto es lo que se usa internamente para implementar el famoso {:?}
formateador.
** ACTUALIZACIÓN ** Esto no se ha verificado que funcione recientemente.
Junté una pequeña caja para hacer esto basada en la respuesta de vbo. Le da una macro para devolver o imprimir el tipo.
Ponga esto en su archivo Cargo.toml:
[dependencies]
t_bang = "0.1.2"
Entonces puedes usarlo así:
#[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"
}
#![feature]
no se puede utilizar en el canal de liberación estable`
También puede usar el enfoque simple de usar la variable en println!("{:?}", var)
. Si Debug
no se implementa para el tipo, puede ver el tipo en el mensaje de error del compilador:
mod some {
pub struct SomeType;
}
fn main() {
let unknown_var = some::SomeType;
println!("{:?}", unknown_var);
}
( parque infantil )
Está sucio pero funciona.
Debug
no se implementa , este es un caso bastante poco probable. Una de las primeras cosas que debe hacer para la mayoría de las estructuras es agregar #[derive(Debug)]
. Creo que los tiempos en los que no quieres Debug
son muy pequeños.
println!("{:?}", unknown_var);
? ¿Es una interpolación de cuerdas pero por qué :?
dentro de las llaves? @DenisKolodin
Debug
porque no está implementado, pero también puedes usarlo {}
.
Hay una respuesta @ChrisMorgan para obtener un tipo aproximado ("flotación") en óxido estable y hay una respuesta @ShubhamJain para obtener un tipo preciso ("f64") a través de una función inestable en óxido nocturno.
Ahora aquí hay una forma en que uno puede obtener el tipo preciso (es decir, decidir entre f32 y f64) en óxido estable:
fn main() {
let a = 5.;
let _: () = unsafe { std::mem::transmute(a) };
}
resultados en
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)
Actualizar
La variación del turbocebo
fn main() {
let a = 5.;
unsafe { std::mem::transmute::<_, ()>(a) }
}
es ligeramente más corto pero algo menos legible.
float
, decir entre f32
y f64
se puede lograr constd::mem::size_of_val(&a)
Algunas otras respuestas no funcionan, pero me parece que el nombre de tipo cajón funciona.
Crea un nuevo proyecto:
cargo new test_typename
Modificar el Cargo.toml
[dependencies]
typename = "0.1.1"
Modifica tu código fuente
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());
}
El resultado es:
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
typename
no funciona con variables sin tipo explícito en la declaración. Ejecutarlo my_number
desde la pregunta da el siguiente error "no se puede llamar al método type_name_of
en tipo numérico ambiguo {float}
. Ayuda: debe especificar un tipo para este enlace, como f32
"
0.65
y funciona bien: type of c 0.65 0.65 is f64
. Aquí está mi versión:rustc 1.38.0-nightly (69656fa4c 2019-07-13)
Si solo quiere saber el tipo de su variable durante el desarrollo interactivo, le recomiendo usar rls (servidor de lenguaje de óxido) dentro de su editor o ide. Luego, puede habilitar o alternar permanentemente la capacidad de desplazamiento y simplemente colocar el cursor sobre la variable. Debería aparecer un pequeño cuadro de diálogo con información sobre la variable, incluido el tipo.
:?
ha sido implementado manualmente durante bastante tiempo. Pero lo más importante, lastd::fmt::Debug
implementación (para eso es lo que:?
usa) para los tipos de números ya no incluye un sufijo para indicar de qué tipo es.