Skip to main content

Rust

Day 4: Printing Custom types

Welcome back, fellow Rustaceans 🦀!

Last time, we explored formatting options provided by the Rust std::fmt library. We saw how placeholders make it easy to print different types without needing C-style formatters like %d. Additionally, we learned how to use features like {:x} to customize the output format (e.g., hexadecimal). Finally, we got a glimpse of the Debug trait and how it allows us to automatically derive default formatting for custom data types.

Today, we'll delve deeper into Debug and Display, Rust's way of extending formatted prints to our custom data types.

So, you might be wondering why the ability to print custom data types is so important. Printing custom data types like structures is crucial for debugging, analysis, and user communication. During the development process, printing the contents of a structure offers invaluable insights into the program's internal state. This allows you to track variable values, verify that your code manipulates data correctly, and pinpoint the root of potential errors. Additionally, printing the contents of structures can be used to generate logs or reports that present complex information in a human-readable format, enhancing the overall understanding of the program's output.

Okay, let's take a look at how we would print a custom data type in C.

#include <stdio.h>

// Define the structure
struct Book {
    char title[50];
    char author[50];
    int year;
};

int main() {
    // Create a structure variable
    struct Book myBook = {"The Hobbit", "J.R.R. Tolkien", 1937};

    // Print the structure members
    printf("Title: %s\n", myBook.title);
    printf("Author: %s\n", myBook.author);
    printf("Year: %d\n", myBook.year);

    return 0;
}

Here we start by defining the Book structure with members titleauthor, and year to represent the information about a book. In the main function, we create a Book variable named myBook and initialize it with sample data. We use printf, and the dot operator (.) to access and print the individual members of the myBook structure. The %s format specifier is used for strings (title and author), and %d is used for the integer (year).

While the C approach offers basic functionality, it has limitations. Manually accessing and printing each member can become tedious. Obviously, each of the files defining these structures could define a custom function that takes the structure to be printed as an argument and then handles the printing. The problem with this approach is that it lacks universality and makes it difficult to achieve consistency. Since this is a common use case for debugging and logging, most modern languages try to provide a unified solution. Rust, like many modern languages, abstracts this using the Debug, and Display traits.

As dictated in the previous article you can think of traits as a way for Rust to define behavior like how to print a specific type of data. Rust's Debug and Display traits provide a more elegant solution. By implementing these traits for your structures, you can print them using a single placeholder ({:?} for Debug and {} for Display). This centralizes formatting logic and improves readability. Moreover, you can customize the output format for different use cases. Debug provides a detailed, internal representation suitable for debugging, while Display allows for user-friendly output control. This separation of concerns simplifies printing and promotes cleaner, more maintainable code.

Debug Trait