Ich habe Folgendes:
let mut my_number = 32.90;
Wie drucke ich den Typ von my_number
aus?
Die Verwendung von type
und type_of
hat nicht funktioniert. Gibt es einen anderen Weg, um den Typ der Zahl auszudrucken?
Ich habe Folgendes:
let mut my_number = 32.90;
Wie drucke ich den Typ von my_number
aus?
Die Verwendung von type
und type_of
hat nicht funktioniert. Gibt es einen anderen Weg, um den Typ der Zahl auszudrucken?
Sie können die std::any::type_name
Funktion verwenden. Hierfür ist kein Nightly-Compiler oder externe Crate erforderlich, und die Ergebnisse sind ziemlich korrekt:
fn print_type_of(_: &T) {
println!("{}", std::any::type_name::())
}
fn main() {
let s = "Hallo";
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::); // playground::print_type_of
print_type_of(&{ || "Hallo!" }); // playground::main::{{closure}}
}
Seien Sie gewarnt: Wie in der Dokumentation erwähnt, sollte diese Information nur für Debugging-Zwecke verwendet werden:
Dies ist für diagnostische Zwecke gedacht. Der genaue Inhalt und das Format des Strings sind nicht spezifiziert, außer dass es eine bestmögliche Beschreibung des Typs ist.
Wenn Sie möchten, dass Ihre Typ-Repräsentation zwischen Compiler-Versionen gleich bleibt, sollten Sie ein Trait verwenden, ähnlich wie in der Antwort von phicr.
Wenn Sie lediglich den Typ einer Variablen ermitteln möchten und bereit sind, dies zur Kompilierzeit zu tun, können Sie einen Fehler verursachen und den Compiler dazu bringen, dies aufzuheben.
Zum Beispiel, [setzen Sie die Variable auf einen Typ, der nicht funktioniert](https://play.rust-lang.org/?code=fn%20main()%20%7B%0A%20%20%20%20let%20mut%20my_number%3A%20()%20%3D%2032.90%3B%0A%7D&version=stable&backtrace=2&run=1):
let mut my_number: () = 32.90;
// let () = x; würde auch funktionieren
Fehler[E0308]: unpassende Typen
--> src/main.rs:2:29
|
2 | let mut my_number: () = 32.90;
| ^^^^^ erwartet (), gefunden Gleitkommazahl
|
= Hinweis: Erwarteter Typ `()`
Gefundener Typ `{float}`
Oder [rufen Sie eine ungültige Methode auf](https://play.rust-lang.org/?code=fn%20main()%20%7B%0A%20%20%20%20let%20mut%20my_number%20%3D%2032.90%3B%0A%20%20%20%20my_number.what_is_this()%3B%0A%7D&version=stable&backtrace=2&run=1):
let mut my_number = 32.90;
my_number.what_is_this();
Fehler[E0599]: keine Methode mit dem Namen `what_is_this` für den Typ `{float}` im aktuellen Gültigkeitsbereich gefunden
--> src/main.rs:3:15
|
3 | my_number.what_is_this();
| ^^^^^^^^^^^^
Oder [zugreifen auf ein ungültiges Feld](https://play.rust-lang.org/?code=fn%20main()%20%7B%0A%20%20%20%20let%20mut%20my_number%20%3D%2032.90%3B%0A%20%20%20%20my_number.what_is_this%0A%7D&version=stable&backtrace=2&run=1):
let mut my_number = 32.90;
my_number.what_is_this
Fehler[E0610]: `{float}` ist ein primitiver Typ und hat daher keine Felder
--> src/main.rs:3:15
|
3 | my_number.what_is_this
| ^^^^^^^^^^^^
Diese offenbaren den Typ, der in diesem Fall tatsächlich nicht vollständig aufgelöst ist. Es wird im ersten Beispiel als "Gleitkommavariable" bezeichnet und in allen drei Beispielen als "{float}
"; dies ist ein teilweise aufgelöster Typ, der letztendlich zu f32
oder f64
führen könnte, je nach Verwendung. "{float}" ist kein gültiger Typname, sondern ein Platzhalter, der bedeutet "Ich bin mir nicht ganz sicher, was das ist", aber es handelt sich tatsächlich um eine Gleitkommazahl. Im Fall von Gleitkommavariablen wird der Typ default auf f64
¹ festgelegt, wenn Sie ihn nicht einschränken. (Ein nicht qualifizierter Ganzzahlliterale wird standardmäßig zu i32
.)
Siehe auch:
¹ Es gibt wahrscheinlich noch Möglichkeiten, den Compiler zu verwirren, sodass er nicht zwischen f32
und f64
entscheiden kann; Ich bin mir nicht sicher. Es war früher so einfach wie 32.90.eq(&32.90)
, aber das behandelt beide jetzt als f64
und funktioniert ohne Probleme, also weiß ich nicht.
Es gibt eine instabile Funktion std::intrinsics::type_name
, die den Namen eines Typs zurückgeben kann, obwohl Sie eine nächtliche Version von Rust verwenden müssen (dies wird wahrscheinlich niemals in der stabilen Version von Rust funktionieren). Hier ist ein Beispiel:%3B%0A%7D%0A%0Afn%20main()%20%7B%0A%20%20%20%20print_type_of(%2632.90)%3B%20%20%20%20%20%20%20%20%20%20%2F%2F%20prints%20%22f64%22%0A%20%20%20%20print_type_of(%26vec!%5B1%2C%202%2C%204%5D)%3B%20%20%2F%2F%20prints%20%22std%3A%3Avec%3A%3AVec%3Ci32%3E%22%0A%20%20%20%20print_type_of(%26%22foo%22)%3B%20%20%20%20%20%20%20%20%20%20%2F%2F%20prints%20%22%26str%22%0A%7D&version=nightly&backtrace=2&run=1)
#![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"
}
Wenn Sie alle Typen im Voraus kennen, können Sie Traits verwenden, um eine type_of
-Methode hinzuzufügen:
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"
}
}
//...
Keine Intrinsika oder sonst etwas, daher obwohl etwas begrenzter ist dies die einzige Lösung hier, die Ihnen einen String liefert und stabil ist. (siehe Boiethios's Antwort) Es ist jedoch sehr mühsam und berücksichtigt keine Typparameter, daher könnten wir...
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() };
}
Lassen Sie uns es verwenden:
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!(&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!("{}", >::type_name());
println!("{}", <&i32>::type_name());
println!("{}", <&str>::type_name());
}
Ausgabe:
i32
&i32
&&i32
&mut i32
&&mut i32
&mut &i32
f64
&str
&&str
String
Vec
Result
&i32
&str
Wie wäre es mit der Trait-Funktion type_name
, die nützlich ist, um den Typnamen schnell zu erhalten.
pub trait AnyExt {
fn type_name(&self) -> &'static str;
}
impl AnyExt for T {
fn type_name(&self) -> &'static str {
std::any::type_name::()
}
}
fn main(){
let my_number = 32.90;
println!("{}",my_number.type_name());
}
Ausgabe:
f64
Ich schreibe ein Makro type_of!()
zum Debuggen, das ursprünglich von std dbg!()
stammt.
pub fn type_of2(v: T) -> (&'static str, T) {
(std::any::type_name::(), v)
}
#[macro_export]
macro_rules! type_of {
// HINWEIS: Wir können `concat!` nicht verwenden, um einen statischen String als Formatargument von `eprintln!` zu erzeugen, da `file!` eine `{` enthalten könnte oder `$val` ein Block (`{ .. }`) sein könnte, in welchem Fall das `eprintln!` fehlerhaft wäre.
() => {
eprintln!("[{}:{}]", file!(), line!());
};
($val:expr $(,)?) => {
// Die Verwendung von `match` hier ist beabsichtigt, weil es sich auf die Lebensdauern von temporären Variablen auswirkt - https://stackoverflow.com/a/48732525/1063961
match $val {
tmp => {
let (type_,tmp) = $crate::type_of2(tmp);
eprintln!("[{}:{}] {}: {}",
file!(), line!(), stringify!($val), type_);
tmp
}
}
};
($($val:expr),+ $(,)?) => {
($($crate::type_of!($val)),+,)
};
}
fn main(){
let my_number = type_of!(32.90);
type_of!(my_number);
}
Ausgabe:
[src/main.rs:32] 32.90: f64
[src/main.rs:33] my_number: f64
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.