Answers:
如果仅希望找出变量的类型并愿意在编译时进行操作,则可能会导致错误并让编译器选择它。
例如,将变量设置为无效的类型:
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
可以为您提供类型的名称,尽管您必须每晚使用Rust构建(这在稳定的Rust中不太可能起作用)。这是一个例子:
#![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}}
}
警告:如文档中所述,此信息只能用于调试目的:
这旨在用于诊断。字符串的确切内容和格式未指定,只是尽力描述该类型。
如果希望类型表示在编译器版本之间保持不变,则应使用trait,如phicr的answer所示。
如果您事先知道所有类型,则可以使用特征添加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以下内容不再起作用。检查Shubham的答案以进行更正。
结帐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
未实施 -这是极不可能的情况。对于大多数结构,您应该做的第一件事就是add #[derive(Debug)]
。我认为您不想要的时间Debug
很少。
println!("{:?}", unknown_var);
吗?是字符串插值,但为什么:?
在花括号内?@DenisKolodin
Debug
之所以使用它,是因为它尚未实现,但您也可以使用{}
。
有一个@ChrisMorgan 答案可以在稳定的锈蚀中获得近似类型(“ float”),还有一个@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)
更新资料
turbo鱼变种
fn main() {
let a = 5.;
unsafe { std::mem::transmute::<_, ()>(a) }
}
略短一些,但可读性较差。
float
,就可以进行交流,f32
并且f64
可以完成std::mem::size_of_val(&a)
一些其他的答案没有工作,但我发现typename的板条箱的工作原理。
创建一个新项目:
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)
:?
现在已经有相当长的时间是手动执行的。但更重要的std::fmt::Debug
是:?
,数字类型的实现(为此使用的是)不再包含后缀以表明其属于哪种类型。