Ho il seguente:
let mut my_number = 32.90;
Come si stampa il tipo di my_number
?
Utilizzo type
e type_of
non ha funzionato. C'è un altro modo in cui posso stampare il tipo di numero?
Ho il seguente:
let mut my_number = 32.90;
Come si stampa il tipo di my_number
?
Utilizzo type
e type_of
non ha funzionato. C'è un altro modo in cui posso stampare il tipo di numero?
Risposte:
Se desideri semplicemente scoprire il tipo di una variabile e sei disposto a farlo al momento della compilazione, puoi causare un errore e far sì che il compilatore lo raccolga.
Ad esempio, imposta la variabile su un tipo che non funziona :
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}`
Oppure chiama un metodo non valido :
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 accedi a un campo non valido :
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
| ^^^^^^^^^^^^
Questi rivelano il tipo, che in questo caso in realtà non è stato completamente risolto. Si chiama "variabile in virgola mobile" nel primo esempio e " {float}
" in tutti e tre gli esempi; questo è un tipo parzialmente risolto che potrebbe finire f32
o f64
, a seconda di come lo usi. “ {float}
” Non è un nome di tipo legale, è un segnaposto che significa “Non sono del tutto sicuro di cosa si tratti”, ma è un numero in virgola mobile. Nel caso di variabili a virgola mobile, se non lo si vincola, l'impostazione predefinita è f64
¹. (Un valore intero intero non qualificato verrà automaticamente impostato su i32
.)
Guarda anche:
¹ Potrebbero esserci ancora modi per confondere il compilatore in modo che non possa decidere tra f32
e f64
; Non ne sono sicuro. In passato era semplice 32.90.eq(&32.90)
, ma questo tratta sia come f64
ora che in allegria, quindi non lo so.
ImageBuffer<_, Vec<_>>
che non mi aiuta molto quando sto provando a scrivere una funzione che accetta una di queste cose come parametro. E questo accade nel codice che altrimenti viene compilato fino a quando non aggiungo il file :()
. Non c'è modo migliore?
C'è una funzione instabile std::intrinsics::type_name
che può darti il nome di un tipo, anche se devi usare una build notturna di Rust (è improbabile che funzioni mai in Rust stabile). Ecco un esempio:
#![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
sta prendendo referenze ( &T
), non valori ( T
), quindi devi passare &&str
piuttosto che &str
; cioè print_type_of(&"foo")
piuttosto che print_type_of("foo")
.
std::any::type_name
è stabile dalla ruggine 1,38: stackoverflow.com/a/58119924
Puoi usare la std::any::type_name
funzione. Ciò non richiede un compilatore notturno o una cassa esterna e i risultati sono abbastanza corretti:
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}}
}
Attenzione: come indicato nella documentazione, queste informazioni devono essere utilizzate solo a scopo di debug:
Questo è inteso per uso diagnostico. Il contenuto esatto e il formato della stringa non sono specificati, oltre ad essere una descrizione del tipo più efficace.
Se vuoi che la tua rappresentazione del tipo rimanga la stessa tra le versioni del compilatore, dovresti usare un tratto, come nella risposta di phicr .
Se conosci in anticipo tutti i tipi, puoi utilizzare i tratti per aggiungere un type_of
metodo:
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"
}
}
//...
Nessun intrisics o niente, quindi anche se più limitato, questa è l'unica soluzione che ti dà una stringa ed è stabile. (vedi la risposta di Boiethios in francese ) Tuttavia, è molto laborioso e non tiene conto dei parametri del tipo, quindi potremmo ...
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() };
}
Usiamolo:
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());
}
produzione:
i32
&i32
&&i32
&mut i32
&&mut i32
&mut &i32
f64
&str
&&str
String
Vec<i32>
Result<String,i64>
&i32
&str
UPD Quanto segue non funziona più. Controlla la risposta di Shubham per la correzione.
Partenza std::intrinsics::get_tydesc<T>()
. È nello stato "sperimentale" in questo momento, ma va bene se stai solo hackerando il sistema di tipi.
Guarda il seguente esempio:
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>"
}
Questo è ciò che viene utilizzato internamente per implementare il famoso {:?}
formattatore.
** AGGIORNAMENTO ** Non è stato verificato che funzioni recentemente.
Ho messo insieme una piccola cassa per farlo in base alla risposta di Vbo. Ti dà una macro per restituire o stampare il tipo.
Inserisci questo nel tuo file Cargo.toml:
[dependencies]
t_bang = "0.1.2"
Quindi puoi usarlo in questo modo:
#[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]
non può essere utilizzato sul canale di rilascio stabile`
Puoi anche usare il semplice approccio dell'uso della variabile in println!("{:?}", var)
. Se Debug
non è implementato per il tipo, è possibile visualizzare il tipo nel messaggio di errore del compilatore:
mod some {
pub struct SomeType;
}
fn main() {
let unknown_var = some::SomeType;
println!("{:?}", unknown_var);
}
( box )
È sporco ma funziona.
Debug
non è implementato , questo è un caso abbastanza improbabile. Una delle prime cose che dovresti fare per quasi tutte le strutture è aggiungere #[derive(Debug)]
. Penso che i tempi in cui non vuoi Debug
siano molto piccoli.
println!("{:?}", unknown_var);
?? È un'interpolazione di stringhe ma perché :?
all'interno delle parentesi graffe? @DenisKolodin
Debug
perché non è implementato, ma puoi anche usarlo {}
.
C'è una risposta @ChrisMorgan per ottenere un tipo approssimativo ("float") in ruggine stabile e c'è una risposta @ShubhamJain per ottenere un tipo preciso ("f64") attraverso una funzione instabile nella ruggine notturna.
Ora ecco un modo in cui si può ottenere un tipo preciso (cioè decidere tra f32 e f64) in ruggine stabile:
fn main() {
let a = 5.;
let _: () = unsafe { std::mem::transmute(a) };
}
risultati 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)
Aggiornare
La variazione turbofish
fn main() {
let a = 5.;
unsafe { std::mem::transmute::<_, ()>(a) }
}
è leggermente più corto ma un po 'meno leggibile.
float
, dire tra f32
e f64
può essere realizzato constd::mem::size_of_val(&a)
Alcune altre risposte non funzionano, ma trovo che la cassa del nome tipografico funzioni .
Crea un nuovo progetto:
cargo new test_typename
Modifica il Cargo.toml
[dependencies]
typename = "0.1.1"
Modifica il tuo codice sorgente
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());
}
L'output è:
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
non funziona con variabili senza tipo esplicito nella dichiarazione. Eseguendolo con my_number
dalla domanda si ottiene il seguente errore "impossibile chiamare il metodo type_name_of
su un tipo numerico ambiguo {float}
. f32
0.65
e funziona bene: type of c 0.65 0.65 is f64
. ecco la mia versione:rustc 1.38.0-nightly (69656fa4c 2019-07-13)
Se vuoi solo conoscere il tipo di variabile durante lo sviluppo interattivo, ti consiglio caldamente di usare rls (rust language server) all'interno del tuo editor o ide. È quindi possibile semplicemente abilitare permanentemente o attivare l'abilità hover e posizionare il cursore sulla variabile. Una piccola finestra di dialogo dovrebbe fornire informazioni sulla variabile incluso il tipo.
:?
ormai da molto tempo è stato implementato manualmente. Ma soprattutto, l'std::fmt::Debug
implementazione (per questo è ciò che:?
utilizza) per i tipi di numero non include più un suffisso per indicare di quale tipo è.