Saya memiliki yang berikut ini:
let mut my_number = 32.90;
Bagaimana cara saya mencetak jenis my_number
?
Menggunakan type
dan type_of
tidak berhasil. Apakah ada cara lain untuk mencetak jenis nomor itu?
Saya memiliki yang berikut ini:
let mut my_number = 32.90;
Bagaimana cara saya mencetak jenis my_number
?
Menggunakan type
dan type_of
tidak berhasil. Apakah ada cara lain untuk mencetak jenis nomor itu?
Jawaban:
Jika Anda hanya ingin mengetahui jenis variabel dan bersedia melakukannya pada waktu kompilasi, Anda dapat menyebabkan kesalahan dan meminta kompilator untuk mengambilnya.
Misalnya, atur variabel ke tipe yang tidak berfungsi :
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}`
Atau hubungi metode yang tidak valid :
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();
| ^^^^^^^^^^^^
Atau akses bidang yang tidak valid :
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
| ^^^^^^^^^^^^
Ini mengungkapkan jenis, yang dalam hal ini sebenarnya tidak sepenuhnya diselesaikan. Ini disebut "variabel titik-mengambang" pada contoh pertama, dan " {float}
" dalam ketiga contoh; ini adalah jenis yang diselesaikan sebagian yang bisa berakhir f32
atau f64
, tergantung pada bagaimana Anda menggunakannya. " {float}
" Bukan nama jenis hukum, ini adalah placeholder yang berarti "Saya tidak sepenuhnya yakin apa ini", tetapi ini adalah angka floating-point. Dalam kasus variabel floating-point, jika Anda tidak membatasi itu, itu akan default ke f64
¹. (Literal integer yang tidak berkualitas akan default ke i32
.)
Lihat juga:
¹ Mungkin masih ada cara membingungkan penyusun sehingga tidak bisa memutuskan antara f32
dan f64
; Saya tidak yakin. Dulu sesederhana itu 32.90.eq(&32.90)
, tetapi itu memperlakukan baik seperti f64
sekarang dan bersama-sama bahagia, jadi saya tidak tahu.
ImageBuffer<_, Vec<_>>
yang tidak banyak membantu saya ketika saya mencoba menulis fungsi yang menggunakan salah satu dari hal-hal ini sebagai parameter. Dan ini terjadi dalam kode yang jika tidak dikompilasi sampai saya menambahkan :()
. Apakah tidak ada cara yang lebih baik?
Ada fungsi std::intrinsics::type_name
yang tidak stabil yang bisa membuat Anda mendapatkan nama suatu tipe, meskipun Anda harus menggunakan build malam hari Rust (ini tidak mungkin bekerja di Rust yang stabil). Ini sebuah contoh:
#![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
mengambil referensi ( &T
), bukan nilai ( T
), jadi Anda harus lulus &&str
daripada &str
; itu, print_type_of(&"foo")
bukannya print_type_of("foo")
.
std::any::type_name
stabil sejak karat 1.38: stackoverflow.com/a/58119924
Anda dapat menggunakan std::any::type_name
fungsi ini. Ini tidak memerlukan kompiler malam atau peti eksternal, dan hasilnya cukup benar:
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}}
}
Diperingatkan: seperti yang disebutkan dalam dokumentasi, informasi ini harus digunakan hanya untuk tujuan debug:
Ini dimaksudkan untuk penggunaan diagnostik. Isi dan format string yang tepat tidak ditentukan, selain sebagai deskripsi upaya terbaik dari tipe tersebut.
Jika Anda ingin representasi tipe Anda tetap sama di antara versi kompiler, Anda harus menggunakan sifat, seperti dalam jawaban phicr .
Jika Anda tahu semua tipe sebelumnya, Anda bisa menggunakan ciri untuk menambahkan type_of
metode:
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"
}
}
//...
Tidak ada intrik atau apa pun, jadi meskipun lebih terbatas ini adalah satu-satunya solusi di sini yang memberi Anda string dan stabil. (lihat jawaban French Boiethios ) Namun, ini sangat melelahkan dan tidak memperhitungkan parameter tipe, sehingga kami dapat ...
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() };
}
Mari kita gunakan:
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());
}
keluaran:
i32
&i32
&&i32
&mut i32
&&mut i32
&mut &i32
f64
&str
&&str
String
Vec<i32>
Result<String,i64>
&i32
&str
UPD Berikut ini tidak berfungsi lagi. Periksa jawaban Shubham untuk koreksi.
Lihat std::intrinsics::get_tydesc<T>()
. Ini dalam keadaan "eksperimental" sekarang, tetapi tidak apa-apa jika Anda hanya meretas sistem tipe.
Lihat contoh berikut:
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>"
}
Inilah yang digunakan secara internal untuk mengimplementasikan {:?}
formatter yang terkenal .
** PEMBARUAN ** Ini belum diverifikasi untuk berfungsi kapan saja.
Saya mengumpulkan peti kecil untuk melakukan ini berdasarkan jawaban vbo. Ini memberi Anda makro untuk mengembalikan atau mencetak jenis.
Masukkan ini ke file Cargo.toml Anda:
[dependencies]
t_bang = "0.1.2"
Maka Anda dapat menggunakannya seperti ini:
#[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]
tidak dapat digunakan pada saluran rilis stabil`
Anda juga dapat menggunakan pendekatan sederhana menggunakan variabel dalam println!("{:?}", var)
. Jika Debug
tidak diterapkan untuk tipe, Anda bisa melihat tipe dalam pesan kesalahan kompiler:
mod some {
pub struct SomeType;
}
fn main() {
let unknown_var = some::SomeType;
println!("{:?}", unknown_var);
}
( playpen )
Itu kotor tapi berhasil.
Debug
tidak diterapkan - ini adalah kasus yang sangat tidak mungkin. Salah satu hal pertama yang harus Anda lakukan untuk sebagian besar struct adalah menambahkan #[derive(Debug)]
. Saya pikir waktu di mana Anda tidak ingin Debug
sangat kecil.
println!("{:?}", unknown_var);
?? Apakah ini interpolasi string tetapi mengapa bagian :?
dalam kurung keriting? @DenisKolodin
Debug
karena tidak diimplementasikan, tetapi Anda dapat menggunakannya {}
juga.
Ada jawaban @ChrisMorgan untuk mendapatkan tipe perkiraan ("float") dalam karat yang stabil dan ada jawaban @ShubhamJain untuk mendapatkan tipe yang tepat ("f64") melalui fungsi yang tidak stabil pada karat malam.
Sekarang inilah cara orang bisa mendapatkan tipe yang tepat (yaitu memutuskan antara f32 dan f64) dalam karat stabil:
fn main() {
let a = 5.;
let _: () = unsafe { std::mem::transmute(a) };
}
hasil dalam
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)
Memperbarui
Variasi turbofish
fn main() {
let a = 5.;
unsafe { std::mem::transmute::<_, ()>(a) }
}
sedikit lebih pendek tetapi agak kurang mudah dibaca.
float
, mengatakan di antara f32
dan f64
dapat dicapai denganstd::mem::size_of_val(&a)
Beberapa jawaban lain tidak berfungsi, tetapi saya menemukan bahwa kotak ketik berfungsi.
Buat proyek baru:
cargo new test_typename
Ubah Cargo.toml
[dependencies]
typename = "0.1.1"
Ubah kode sumber Anda
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());
}
Outputnya adalah:
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
tidak bekerja dengan variabel tanpa tipe eksplisit dalam deklarasi. Menjalankannya dengan my_number
dari pertanyaan memberikan kesalahan berikut "tidak dapat memanggil metode type_name_of
pada tipe numerik yang ambigu {float}
. Bantuan: Anda harus menentukan tipe untuk pengikatan ini, seperti f32
"
0.65
dan bekerja dengan baik: type of c 0.65 0.65 is f64
. di sini adalah versi saya:rustc 1.38.0-nightly (69656fa4c 2019-07-13)
Jika Anda hanya ingin tahu jenis variabel Anda selama pengembangan interaktif, saya akan sangat menyarankan menggunakan rls (server bahasa karat) di dalam editor atau ide Anda. Anda kemudian dapat secara permanen mengaktifkan atau mengaktifkan kemampuan melayang dan cukup meletakkan kursor Anda di atas variabel. Sebuah dialog kecil akan muncul dengan informasi tentang variabel termasuk jenisnya.
:?
telah cukup lama sekarang telah diimplementasikan secara manual. Tetapi yang lebih penting,std::fmt::Debug
implementasi (untuk itulah yang:?
digunakan) untuk tipe angka tidak lagi menyertakan akhiran untuk menunjukkan tipe yang mana.