如何在Rust中打印变量的类型?

use*_*012 204 types rust

我有以下内容:

let mut my_number = 32.90;
Run Code Online (Sandbox Code Playgroud)

我该如何打印my_number

使用typetype_of没有奏效.还有其他方法可以打印数字的类型吗?

Chr*_*gan 159

如果您只想查找变量的类型并愿意在编译时执行此操作,则可能会导致错误并让编译器将其拾取.

例如,将变量设置为不起作用的类型({float}也可以):

let mut my_number: () = 32.90;
// let () = x; would work too
Run Code Online (Sandbox Code Playgroud)

或者在大多数情况下调用无效方法获取无效字段:

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}`
Run Code Online (Sandbox Code Playgroud)
let mut my_number = 32.90;
my_number.what_is_this();
Run Code Online (Sandbox Code Playgroud)

这些揭示了类型,在这种情况下实际上没有完全解决.它在第一个例子中称为"浮点变量",f32在所有三个例子中称为"" ; 这是一种部分解决的类型,可能会结束f64{float}取决于您如何使用它." f64"不是合法的类型名称,它是占位符,意思是"我不完全确定这是什么",但它一个浮点数.对于浮点变量,如果不限制它,它将默认为i32¹.(非限定整数文字将默认为f32.)


¹可能仍有一些方法让编译器感到困惑,因此它无法在f64和之间作出决定32.90.eq(&32.90); 我不确定.它曾经很简单f64,但是{float}现在和快乐地对待现在和chugs,所以我不知道.

  • 这听起来很像黑客。这实际上是检查变量类型的惯用方法吗? (5认同)
  • `:?`已经有很长一段时间了,现在已经手动实现了.但更重要的是,对于数字类型,`std :: fmt :: Debug`实现(对于那是`:?`使用)不再包含一个后缀来指示它的类型. (4认同)
  • 我尝试使用这些技术来尝试查找表达式的类型,但它并不总是有效,尤其是涉及类型参数时.例如,编译器会告诉我它正在期待一个`ImageBuffer <_,Vec <_ >>`当我尝试编写一个将这些东西作为参数的函数时,它对我没什么帮助.这发生在代码中,否则编译直到我添加`:()`.有没有更好的方法? (2认同)
  • 这似乎有点复杂和不直观.代码编辑器是否会非常困难,例如Emacs在光标位于变量上时提供类型,就像许多其他语言一样?如果编译器可以在出错时告诉类型,当没有任何错误时它肯定也应该知道类型吗? (2认同)
  • @JIXiang:Rust 语言服务器就是向 IDE 提供这些信息,但它还不成熟——它的第一个 alpha 版本只是几天前。是的,这是一种可怕的方法;是的,实现目标的不那么深奥的方法正在稳步出现。 (2认同)

小智 98

有一个不稳定的函数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"
}
Run Code Online (Sandbox Code Playgroud)

  • `std::any::type_name` 自 rust 1.38 起就稳定了:/sf/answers/4068394711/ (16认同)
  • 在每夜生锈(1.3)时,只有在将第一行改为`#![feature(core_intrinsics)]时才有效. (2认同)
  • 在编译/运行时获取某些内容的类型具有有效的用例。例如用于序列化 - 或者只是为了调试目的。那些写下“你永远不应该做这样的事情”的人根本就没有遇到过这些用例本身。 (2认同)

phi*_*icr 49

如果您事先知道所有类型,则可以使用特征添加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"
    }
}

//...
Run Code Online (Sandbox Code Playgroud)

没有内在或没什么',所以虽然更有限,但这是唯一的解决方案,让你一个字符串,并稳定.但是,这非常费力,并没有考虑类型参数,所以我们可以......

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() };
}
Run Code Online (Sandbox Code Playgroud)

我们来使用它:

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());
}
Run Code Online (Sandbox Code Playgroud)

输出:

i32
&i32
&&i32
&mut i32
&&mut i32
&mut &i32
f64
&str
&&str
String
Vec<i32>
Result<String,i64>
&i32
&str
Run Code Online (Sandbox Code Playgroud)

铁锈游乐场

  • @PrajwalDhatwalia 我一直在思考你所说的,我觉得我对这些版本如何相互补充感到满意。特征版本显示了宏版本在幕后所做的事情的简化,使其目标更加清晰。另一方面,宏版本展示了如何使特征版本更通用;这不是唯一的方法,但即使表明这是可能的也是有利的。总而言之,这可能有两个答案,但我觉得整体大于部分之和。 (5认同)

vbo*_*vbo 18

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>"
}
Run Code Online (Sandbox Code Playgroud)

这是内部用于实现着名{:?}格式化程序的内容.


Fre*_*ios 14

您可以使用该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}}
}
Run Code Online (Sandbox Code Playgroud)

  • 对我来说最好的答案,因为大多数开发人员希望将其用于调试目的,例如打印解析失败 (6认同)
  • @Jean-FrançoisFabre 该答案已被编辑。当我写下答案时,另一位推荐了不稳定的内在版本。 (4认同)
  • 另见 std::any::type_name_of_val (2认同)
  • 无法使用它来获取“切片/数组引用”的类型 - `print_type_of(&amp;a[1..]);` (2认同)

mpi*_*olo 13

根据vbo的回答,我把一个小箱子放在一起做这个.它为您提供了一个返回或打印出类型的宏.

把它放在你的Cargo.toml文件中:

[dependencies]
t_bang = "0.1.2"
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

#[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"
}
Run Code Online (Sandbox Code Playgroud)


Tan*_*lam 10

1.38版本新增std::any::type_name

use std::any::type_name;

fn type_of<T>(_: T) -> &'static str {
    type_name::<T>()
}
fn main() {
    let x = 21;
    let y = 2.5;
    println!("{}", type_of(&y));
    println!("{}", type_of(x));
}
Run Code Online (Sandbox Code Playgroud)


小智 8

更新,下面的原始答案

trait function 怎么样type_name,它有助于快速获取类型名称。

pub trait AnyExt {
    fn type_name(&self) -> &'static str;
}

impl<T> AnyExt for T {
    fn type_name(&self) -> &'static str {
        std::any::type_name::<T>()
    }
}

fn main(){
    let my_number = 32.90;
    println!("{}",my_number.type_name());
}
Run Code Online (Sandbox Code Playgroud)

输出:

f64
Run Code Online (Sandbox Code Playgroud)

原答案

我写了一个宏type_of!()来调试,它是原始的 std dbg!()

pub trait AnyExt {
    fn type_name(&self) -> &'static str;
}

impl<T> AnyExt for T {
    fn type_name(&self) -> &'static str {
        std::any::type_name::<T>()
    }
}

fn main(){
    let my_number = 32.90;
    println!("{}",my_number.type_name());
}
Run Code Online (Sandbox Code Playgroud)

输出:

[src/main.rs:32] 32.90: f64
[src/main.rs:33] my_number: f64
Run Code Online (Sandbox Code Playgroud)


Den*_*din 7

您还可以使用使用变量的简单方法println!("{:?}", var).如果Debug没有为类型实现,您可以在编译器的错误消息中看到类型:

mod some {
    pub struct SomeType;
}

fn main() {
    let unknown_var = some::SomeType;
    println!("{:?}", unknown_var);
}
Run Code Online (Sandbox Code Playgroud)

(围栏)

它很脏但是有效.

  • *如果没有实现`Debug`* - 这是一个非常不可能的情况.对于大多数结构,你应该做的第一件事就是添加`#[derive(Debug)]`.我认为你不想要`Debug`的时间非常小. (7认同)

Ant*_*ins 5

有一个 @ChrisMorgan答案可以在稳定的 rust 中获得近似类型(“float”),有一个 @ShubhamJain答案可以通过夜间 rust 中的不稳定函数获得精确类型(“f64”)。

现在有一种方法可以在稳定的 Rust 中获得精确的类型(即在 f32 和 f64 之间做出决定):

fn main() {
    let a = 5.;
    let _: () = unsafe { std::mem::transmute(a) };
}
Run Code Online (Sandbox Code Playgroud)

结果是

fn main() {
    let a = 5.;
    let _: () = unsafe { std::mem::transmute(a) };
}
Run Code Online (Sandbox Code Playgroud)

更新

涡轮鱼的变种

fn main() {
    let a = 5.;
    unsafe { std::mem::transmute::<_, ()>(a) }
}
Run Code Online (Sandbox Code Playgroud)

稍微短一些,但可读性稍差。


nrd*_*dxp 5

如果您只是想在交互式开发过程中了解变量的类型,我强烈建议您在编辑器或 IDE 中使用rls (Rust 语言服务器)。然后,您可以简单地永久启用或切换悬停功能,并将光标放在变量上。一个小对话框应该会显示有关变量的信息,包括类型。