J'ai ce qui suit:
let mut my_number = 32.90;
Comment imprimer le type de my_number
?
Utilisation type
et type_of
n'a pas fonctionné. Existe-t-il une autre façon d'imprimer le type du numéro?
J'ai ce qui suit:
let mut my_number = 32.90;
Comment imprimer le type de my_number
?
Utilisation type
et type_of
n'a pas fonctionné. Existe-t-il une autre façon d'imprimer le type du numéro?
Réponses:
Si vous souhaitez simplement découvrir le type d'une variable et êtes prêt à le faire lors de la compilation, vous pouvez provoquer une erreur et demander au compilateur de la récupérer.
Par exemple, définissez la variable sur un type qui ne fonctionne pas :
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}`
Ou appelez une méthode non valide :
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();
| ^^^^^^^^^^^^
Ou accédez à un champ invalide :
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
| ^^^^^^^^^^^^
Ceux-ci révèlent le type, qui dans ce cas n'est en fait pas entièrement résolu. Cela s'appelle «variable à virgule flottante» dans le premier exemple et « {float}
» dans les trois exemples; il s'agit d'un type partiellement résolu qui pourrait finir f32
ou f64
, selon la façon dont vous l'utilisez. « {float}
» Est pas un nom de type juridique, il est un espace réservé qui signifie « Je suis sûr que pas tout à fait ce que cela est », mais il est un nombre à virgule flottante. Dans le cas des variables à virgule flottante, si vous ne la contraignez pas, elle sera par défaut f64
¹. (Un littéral entier non qualifié sera défini par défaut sur i32
.)
Voir également:
¹ Il peut encore y avoir des moyens de dérouter le compilateur pour qu'il ne puisse pas décider entre f32
et f64
; Je ne suis pas sûr. Auparavant, c'était aussi simple que cela 32.90.eq(&32.90)
, mais cela traite à la fois comme f64
maintenant et se déroule joyeusement, donc je ne sais pas.
ImageBuffer<_, Vec<_>>
qui ne m'aide pas beaucoup lorsque j'essaie d'écrire une fonction qui prend l'une de ces choses comme paramètre. Et cela se produit dans du code qui autrement se compile jusqu'à ce que j'ajoute le :()
. N'y a-t-il pas de meilleur moyen?
Il existe une fonction instable std::intrinsics::type_name
qui peut vous donner le nom d'un type, bien que vous deviez utiliser une version nocturne de Rust (cela ne fonctionnera probablement jamais dans Rust stable). Voici un exemple:
#![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
prend des références ( &T
), pas des valeurs ( T
), vous devez donc passer &&str
plutôt que &str
; c'est print_type_of(&"foo")
plutôt que print_type_of("foo")
.
std::any::type_name
est stable depuis la rouille 1.38: stackoverflow.com/a/58119924
Vous pouvez utiliser la std::any::type_name
fonction. Cela n'a pas besoin d'un compilateur nocturne ou d'une caisse externe, et les résultats sont tout à fait corrects:
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}}
}
Attention: comme indiqué dans la documentation, ces informations ne doivent être utilisées qu'à des fins de débogage:
Ceci est destiné à un usage diagnostique. Le contenu exact et le format de la chaîne ne sont pas spécifiés, à part une description du type au mieux.
Si vous voulez que votre représentation de type reste la même entre les versions du compilateur, vous devez utiliser un trait, comme dans la réponse du phicr .
Si vous connaissez tous les types au préalable, vous pouvez utiliser des traits pour ajouter une type_of
méthode:
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"
}
}
//...
Pas d'intrication ou rien, donc bien que plus limité, c'est la seule solution ici qui vous donne une chaîne et est stable. (voir la réponse du français Boiethios ) Cependant, c'est très laborieux et ne tient pas compte des paramètres de type, donc nous pourrions ...
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() };
}
Utilisons-le:
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());
}
production:
i32
&i32
&&i32
&mut i32
&&mut i32
&mut &i32
f64
&str
&&str
String
Vec<i32>
Result<String,i64>
&i32
&str
UPD Ce qui suit ne fonctionne plus. Vérifiez la réponse de Shubham pour correction.
Découvrez std::intrinsics::get_tydesc<T>()
. Il est actuellement dans un état "expérimental", mais ce n'est pas grave si vous piratez simplement le système de type.
Découvrez l'exemple suivant:
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>"
}
C'est ce qui est utilisé en interne pour implémenter le célèbre {:?}
formateur.
** MISE À JOUR ** Cela n'a pas été vérifié pour fonctionner à tout moment récemment.
J'ai mis en place une petite caisse pour le faire en fonction de la réponse de vbo. Il vous donne une macro pour retourner ou imprimer le type.
Mettez ceci dans votre fichier Cargo.toml:
[dependencies]
t_bang = "0.1.2"
Ensuite, vous pouvez l'utiliser comme ceci:
#[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]
ne peut pas être utilisé sur le canal de sortie stable»
Vous pouvez également utiliser l'approche simple consistant à utiliser la variable dans println!("{:?}", var)
. Si Debug
n'est pas implémenté pour le type, vous pouvez voir le type dans le message d'erreur du compilateur:
mod some {
pub struct SomeType;
}
fn main() {
let unknown_var = some::SomeType;
println!("{:?}", unknown_var);
}
( parc )
C'est sale mais ça marche.
Debug
n'est pas implémenté - c'est un cas assez improbable cependant. L'une des premières choses que vous devriez faire pour la plupart des structures est d'ajouter #[derive(Debug)]
. Je pense que les moments où vous ne voulez pas Debug
sont très petits.
println!("{:?}", unknown_var);
?? Est-ce une interpolation de chaîne mais pourquoi l' :?
intérieur des accolades? @DenisKolodin
Debug
car il n'est pas implémenté, mais vous pouvez également l'utiliser {}
.
Il y a une réponse @ChrisMorgan pour obtenir le type approximatif ("float") dans la rouille stable et il y a une réponse @ShubhamJain pour obtenir le type précis ("f64") grâce à la fonction instable dans la rouille nocturne.
Maintenant, voici un moyen d'obtenir un type précis (c'est-à-dire de choisir entre f32 et f64) dans la rouille stable:
fn main() {
let a = 5.;
let _: () = unsafe { std::mem::transmute(a) };
}
résulte 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)
Mettre à jour
La variation du turbofish
fn main() {
let a = 5.;
unsafe { std::mem::transmute::<_, ()>(a) }
}
est légèrement plus court mais un peu moins lisible.
float
, dire entre f32
et f64
peut être accompli avecstd::mem::size_of_val(&a)
D'autres réponses ne fonctionnent pas, mais je trouve que le typename fonctionne caisse.
Créez un nouveau projet:
cargo new test_typename
Modifier le Cargo.toml
[dependencies]
typename = "0.1.1"
Modifiez votre code source
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());
}
La sortie est:
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
ne fonctionne pas avec des variables sans type explicite dans la déclaration. L'exécuter avec my_number
la question donne l'erreur suivante "impossible d'appeler la méthode type_name_of
sur un type numérique ambigu {float}
. Aide: vous devez spécifier un type pour cette liaison, comme f32
"
0.65
et il fonctionne bien: type of c 0.65 0.65 is f64
. voici ma version:rustc 1.38.0-nightly (69656fa4c 2019-07-13)
Si vous voulez juste connaître le type de votre variable pendant le développement interactif, je vous recommande fortement d'utiliser rls (rust language server) dans votre éditeur ou ide. Vous pouvez ensuite simplement activer ou basculer de manière permanente la capacité de survol et placer simplement votre curseur sur la variable. Une petite boîte de dialogue devrait fournir des informations sur la variable, y compris le type.
:?
est depuis longtemps mis en œuvre manuellement. Mais plus important encore, l'std::fmt::Debug
implémentation (car c'est ce qui est:?
utilisé) pour les types de nombres n'inclut plus de suffixe pour indiquer de quel type il s'agit.