How to Print the Type of a Variable in Rust

1. Overview

Data types are essential components of virtually every programming language. Rust is a strongly typed language with various built-in types. While modern IDEs often help preview variable types, there may be cases where we need to programmatically determine a variable’s type, particularly for debugging purposes.
In this tutorial, we’ll learn how to use Rust’s built-in library to print the type of a variable.

2. Using type_name()

The type_name() function provided by the Rust standard library can be used to print the type of a variable. First, we need to import the necessary function:

use std::any::type_name;

To demonstrate its usage, let’s define a helper function named print_type_of(). This function accepts a generic parameter T and uses type_name() to print its type. The underscore parameter name indicates we don’t use the actual value:

fn print_type_of<T>(_: &T) {
    println!("{}", type_name::<T>());
}

Let’s define some variables and use print_type_of() to display their types:

let number = 32.90;
let greeting = "Hello World!";
let publishers = vec!["Springer", "Healthline"];

print_type_of(&number);
print_type_of(&greeting);
print_type_of(&publishers);

When we ran this code, we saw the following output:

f64
&str
alloc::vec::Vec<&str>

In the output above, we saw the float, string, and Vec<> type.

3. Using Compiler Errors to Determine Types

Another way to determine types is to cause a compile-time type mismatch intentionally. For example, we can try assigning values to variables explicitly typed as the unit type ():

let number: () = 32.90;
let greeting: () = "Hello World!";
let publishers: () = vec!["Springer", "Healthline"];

When we attempt to compile this code, the compiler will produce errors that reveal the actual types:

error[E0308]: mismatched types
|
| let number: () = 32.90;
| ^^^^^ expected `()`, found floating-point number
|
error[E0308]: mismatched types
|
| let greeting: () = "Hello World!";
| ^^^^^^^^^^^^^^ expected `()`, found `&str`
|
error[E0308]: mismatched types
|
| let publishers: () = vec!["Springer", "Healthline"];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Vec<&str>`

This compile-time error approach can be particularly useful during development when we’re working with complex types or trying to understand type inference in our code.

4. Best Practices

  • We should use type_name() when we need type information at runtime, such as in logging or debugging scenarios
  • We should consider using compiler errors during development when we’re trying to understand type inference
  • Notably, print_type_of function takes references to avoid taking ownership of the values

5. Conclusion

In this article, we’ve explored two effective methods for determining variable types in Rust:

  • Using the std::any::type_name function for runtime type information
  • Leveraging compiler error messages during development

Both approaches serve different purposes and can be valuable tools in our Rust debugging toolkit. The type_name approach is more suitable for production code when type information is needed at runtime, while the compiler error method is helpful during the development and learning phases.