Learning Rust 🦀: 11 - Debugging custom types/Structs
Tags: learning, rust, programming, development
Published: 2023-08-25 16:36:12

In this short article, we will see how we can print our structs / custom types for debugging proposes building on the knowledge from [the last article](https://dev.to/fadygrab/learning-rust-10-the-struct-1efd). This article is so short that it doesn't need a table of contents 😉. But don't get me wrong, it is still an important topic. Let's begin.

>#### ⚠️ Remember!
You can find all the code snippets for this series in its [accompanying repo](https://github.com/FadyGrAb/rust-learning-series)  
If you don't want to install Rust locally, you can play with all the code of this series in the official [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021) that can be found on its official page.

> ⚠️⚠️ The articles in this series are loosely following the contents of "The Rust Programming Language, 2nd Edition" by Steve Klabnik and Carol Nichols in a way that reflects my understanding from a Python developer's perspective.

⭐ I try to publish a new article every week (maybe more if the Rust gods 🙌 are generous 😁) so stay tuned 😉. I'll be posting "new articles updates" on my [LinkedIn](https://www.linkedin.com/in/fady-abdelmassih) and [Twitter](https://twitter.com/fadyGrAb).

We will start by creating our custom "Car" type and try to print it:
```rust
struct Car {
    maker: String,
    model: String,
    year_of_making: u16,
    max_speed_kph: u16,
}
fn main() {
    let my_car = Car {
        maker: String::from("Maker1"),
        model: String::from("Model1"),
        year_of_making: 2023,
        max_speed_kph: 190,
    };

    println!("{my_car}");
}
```
This won't go as we have anticipated! We will receive the following compile error:
```
rror[E0277]: `Car` doesn't implement `std::fmt::Display`
  --> src/main.rs:15:15
   |
15 |     println!("{my_car}");
   |               ^^^^^^^^ `Car` cannot be formatted with the default formatter
   |
   = help: the trait `std::fmt::Display` is not implemented for `Car`
   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
```
Let's break it down. the `println!` macro implements **formatters** when using the curly brackets "{}" within it. For primitive types like the integer `1`, it is implemented by default. After all, there aren't that many ways you want to display the number `1` to the user 🤷‍♂️. But for custom types, Rust doesn't know how it should format them. Should it print it as a list, comma separated, some of its properties or all of them? So, rust won't take that guess and the `Display` formatting must be provided in order to print this type.  
But we also get a **note** withing the error message, we may be able to use `{:?}` in order to "Display" our type, so let's try that:
```rust
struct Car {
    maker: String,
    model: String,
    year_of_making: u16,
    max_speed_kph: u16,
}
fn main() {
    let my_car = Car {
        maker: String::from("Maker1"),
        model: String::from("Model1"),
        year_of_making: 2023,
        max_speed_kph: 190,
    };

    println!("{my_car:?}");
}

```
Aaaand we get a compilation error ... again 🤦‍♂️! This time with a different issue.
```
error[E0277]: `Car` doesn't implement `Debug`
  --> src/main.rs:15:15
   |
15 |     println!("{my_car:?}");
   |               ^^^^^^^^^^ `Car` cannot be formatted using `{:?}`
   |
   = help: the trait `Debug` is not implemented for `Car`
   = note: add `#[derive(Debug)]` to `Car` or manually `impl Debug for Car`
   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Car` with `#[derive(Debug)]`
   |
1  + #[derive(Debug)]
2  | struct Car {
   |
```
Now Rust complains about our Car type doesn't implement the **Debug** trait (we will learn all about traits later). But the message error contains a usefull tip this time, `note: add '#[derive(Debug)]' to 'Car' or manually 'impl Debug for Car'`. It turns out that Rust doesn't provide debug printing out-of-the-box for our custom types. We have to opt-in to that functionality. So, let's do what the tip suggests:
```rust
#[derive(Debug)]
struct Car {
    maker: String,
    model: String,
    year_of_making: u16,
    max_speed_kph: u16,
}
fn main() {
    let my_car = Car {
        maker: String::from("Maker1"),
        model: String::from("Model1"),
        year_of_making: 2023,
        max_speed_kph: 190,
    };

    println!("{my_car:?}");
}
```
Woohoo! Now it runs!
```
Car { maker: "Maker1", model: "Model1", year_of_making: 2023, max_speed_kph: 190 }
```
And if we've used the `{:#?}` operator, our custom Car type will be pretty printed.
```
Car {
    maker: "Maker1",
    model: "Model1",
    year_of_making: 2023,
    max_speed_kph: 190,
}
```

And that is one way to print our custom types for debugging. The other one is to use the `dbg!` macro which differs for the `println!` we know and love as it sends its output to the `stderr` terminal stream as opposed to `println!` which sends its output to the `stdout` terminal stream. One other reason is that `dbg!` takes ownership of any passed values to it then returns them back as opposed to `println!` which only takes a reference of the value.  
So, building upon what we have so far, we can use `dbg!` in our previous example like so:
```rust
#[derive(Debug)]
struct Car {
    maker: String,
    model: String,
    year_of_making: u16,
    max_speed_kph: u16,
}
fn main() {
    let my_car = Car {
        maker: String::from("Maker1"),
        model: String::from("Model1"),
        year_of_making: 2023,
        max_speed_kph: dbg!(4 * 50),
    };
    dbg!(&my_car);
}
```
We will get the following output:
```
[src/main.rs:13] 4 * 50 = 200
[src/main.rs:18] &my_car = Car {
    maker: "Maker1",
    model: "Model1",
    year_of_making: 2023,
    max_speed_kph: 200,
}
```
`dgb!` prints the line where it was called and prints the expression and its value. For the first `dbg!`, it's perfectly fine to write it as we did because as we've mentioned, it returns back the value of the expression we've passed to it. And for the second `dbg!` call, we've passed a reference of `my_car` as we didn't want for it to take ownership over our type.  

And that's it 🙂. In the next article, we will talk about enums and pattern matching ... Good stuff 👌👌! See you then 👋.