У мене є таке:
let mut my_number = 32.90;
Як надрукувати тип my_number
?
Користуватися type
і type_of
не вийшло. Чи є інший спосіб я надрукувати тип номера?
У мене є таке:
let mut my_number = 32.90;
Як надрукувати тип my_number
?
Користуватися type
і type_of
не вийшло. Чи є інший спосіб я надрукувати тип номера?
Відповіді:
Якщо ви просто хочете дізнатись тип змінної і готові зробити це під час компіляції, ви можете викликати помилку і змусити компілятора взяти її.
Наприклад, встановіть змінну типу, який не працює :
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}`
Або викличте недійсний метод :
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();
| ^^^^^^^^^^^^
Або отримати доступ до недійсного поля :
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
| ^^^^^^^^^^^^
Вони розкривають тип, який у даному випадку фактично не вирішений повністю. Це називається "змінною з плаваючою комою" у першому прикладі та " {float}
" у всіх трьох прикладах; це частково вирішений тип, який може закінчитися f32
або f64
, залежно від того, яким чином ви його використовуєте. « {float}
» Чи не є ім'я правового типу, це означає заповнювач «Я не зовсім впевнений , що це», але це число з плаваючою крапкою. У випадку змінних з плаваючою комою, якщо ви не обмежуєте її, вона за замовчуванням буде f64
¹. (Некваліфікований цілочисельний літерал за замовчуванням буде i32
.)
Дивитися також:
¹ Ще можуть існувати способи збиття компілятора, щоб він не міг вирішувати між f32
і f64
; Я не впевнений. Раніше це було так просто 32.90.eq(&32.90)
, але це стосується як f64
зараз, так і погладжує щасливо, тому я не знаю.
ImageBuffer<_, Vec<_>>
що це мені не дуже допоможе, коли я намагаюся написати функцію, яка приймає одну з цих речей як параметр. І це відбувається в коді, який інакше компілюється, поки я не додаю :()
. Немає кращого способу?
Існує нестабільна функція, std::intrinsics::type_name
яка може отримати вам назву типу, хоча вам доведеться використовувати нічну збірку іржі (це навряд чи коли-небудь працюватиме в стабільній іржі). Ось приклад:
#![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
бере посилання ( &T
), а не значення ( T
), тож вам потрібно пройти, &&str
а не &str
; тобто, print_type_of(&"foo")
а не print_type_of("foo")
.
std::any::type_name
стабільна після іржі 1,38: stackoverflow.com/a/58119924
Ви можете використовувати std::any::type_name
функцію. Для цього не потрібен нічний компілятор або зовнішня ящик, а результати цілком правильні:
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}}
}
Будьте попереджені: як зазначено в документації, ця інформація повинна використовуватися лише для налагодження:
Це призначено для діагностичного використання. Точний вміст і формат рядка не вказуються, окрім опису типу.
Якщо ви хочете, щоб представлення типу залишалося однаковим між версіями компілятора, вам слід використовувати ознаку, як у відповіді phicr .
Якщо ви заздалегідь знаєте всі типи, можете додати type_of
метод:
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"
}
}
//...
Ніяких інтрисиків чи нічого, тому, хоча більш обмежене, це єдине рішення, яке отримує вам струну та стабільне. (див. відповідь французького Boiethios ) Однак це дуже трудомістко і не враховує параметрів типу, тому ми могли б ...
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() };
}
Давайте використовувати:
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());
}
вихід:
i32
&i32
&&i32
&mut i32
&&mut i32
&mut &i32
f64
&str
&&str
String
Vec<i32>
Result<String,i64>
&i32
&str
UPD Наступне більше не працює. Перевірте відповідь Шубхема на виправлення.
Перевірте std::intrinsics::get_tydesc<T>()
. Зараз він перебуває в "експериментальному" стані, але це нормально, якщо ви просто злому навколо системи типів.
Перегляньте наступний приклад:
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>"
}
Це те, що використовується внутрішньо для реалізації відомого {:?}
форматера.
** ОНОВЛЕННЯ ** Це нещодавно не підтверджено для роботи.
Я зібрав трохи ящика, щоб зробити це на основі відповіді vbo. Це дає вам макрос для повернення або роздрукування типу.
Помістіть це у свій файл Cargo.toml:
[dependencies]
t_bang = "0.1.2"
Тоді ви можете використовувати його так:
#[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]
не можна використовувати на каналі стабільного випуску`
Ви також можете використовувати простий підхід використання змінної в println!("{:?}", var)
. Якщо Debug
цей тип не реалізований, ви можете побачити тип у повідомленні про помилку компілятора:
mod some {
pub struct SomeType;
}
fn main() {
let unknown_var = some::SomeType;
println!("{:?}", unknown_var);
}
( манеж )
Це брудно, але це працює.
Debug
це не реалізовано - це дуже малоймовірний випадок. Одне з перших речей, яке ви повинні зробити для більшості будь-яких структур - це додати #[derive(Debug)]
. Я думаю, що часів, коли ти не хочеш Debug
, дуже мало.
println!("{:?}", unknown_var);
?? Це струнна інтерполяція, але чому :?
всередині фігурні дужки? @DenisKolodin
Debug
тому що він не реалізований, але ви також можете використовувати його {}
.
Там в @ChrisMorgan відповідь отримати приблизний тип ( «поплавок») в стабільній іржі і є @ShubhamJain відповідь , щоб отримати точний тип ( «F64») через нестабільну функцію в нічних іржі.
Тепер ось спосіб отримати точний тип (тобто вирішити між f32 та f64) у стійкій іржі:
fn main() {
let a = 5.;
let _: () = unsafe { std::mem::transmute(a) };
}
призводить до
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)
Оновлення
Варіація турбофіта
fn main() {
let a = 5.;
unsafe { std::mem::transmute::<_, ()>(a) }
}
трохи коротший, але дещо менш читабельний.
float
розповідь між ними f32
та f64
її можна досягтиstd::mem::size_of_val(&a)
Деякі інші відповіді не працюють, але я вважаю, що ящик з набором тексту працює.
Створіть новий проект:
cargo new test_typename
Змініть Cargo.toml
[dependencies]
typename = "0.1.1"
Змініть свій вихідний код
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());
}
Вихід:
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
не працює зі змінними без явного типу в декларації. Якщо запустити його з my_number
запитання, виникає така помилка: "не можна викликати метод type_name_of
неоднозначного числового типу {float}
. f32
0.65
і це добре працює: type of c 0.65 0.65 is f64
. ось моя версія:rustc 1.38.0-nightly (69656fa4c 2019-07-13)
Якщо ви просто хочете дізнатися тип вашої змінної під час інтерактивної розробки, я б дуже рекомендував використовувати rls (сервер мови іржі) всередині вашого редактора або ide. Потім можна просто назавжди ввімкнути або переключити здатність навести курсор і просто навести курсор на змінну. У невеликому діалоговому вікні має з’явитися інформація про змінну, включаючи тип.
:?
вже досить давно впроваджується вручну. Але ще важливіше, щоstd::fmt::Debug
реалізація (для чого саме:?
використовується) для типів чисел більше не містить суфікс, який вказує, для якого типу він є.