---
title: "10.7 Deriving Debug and printing structs"
description: "Why a struct can't be printed with {} by default, how #[derive(Debug)] enables {:?} and {:#?}, and what derive means as boilerplate the compiler writes."
url: "https://learnrust.net/chapter-10/deriving-debug/"
last_updated: "2026-06-13"
---

# 10.7 Deriving Debug and printing structs

You can build a struct and give it methods. Now try the most natural thing in the world, printing one:

```rust
struct Point {
    x: f64,
    y: f64,
}

fn main() {
    let p = Point { x: 3.0, y: 4.0 };
    println!("{}", p);
}
```

```
error[E0277]: `Point` doesn't implement `std::fmt::Display`
 --> src/main.rs:8:20
  |
8 |     println!("{}", p);
  |                    ^ `Point` cannot be formatted with the default formatter
  |
  = help: the trait `std::fmt::Display` is not implemented for `Point`
  = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
```

The compiler isn't being difficult; it genuinely doesn't know how. Lesson [5.5](https://learnrust.net/chapter-5/formatting-strings/) hinted at this: `{}` needs the type to say how it displays, and a type you just invented hasn't said. Should a `Point` print as `(3, 4)`? `3, 4`? `x=3 y=4`? The compiler can't choose for you, so `{}` (the `Display` formatter, meant for human-facing output) is unavailable until you write that choice yourself, which is a chapter 16 topic.

But notice the `note`: the compiler is already pointing at the answer.

## #[derive(Debug)] and {:?}

There's a second formatter, `{:?}`, the *debug* formatter from lesson [5.5](https://learnrust.net/chapter-5/formatting-strings/), meant for programmers rather than end users. Its job is to show a value's structure so you can inspect it, and the compiler can write that one for you automatically. You ask with a `derive` attribute on the struct:

```rust
#[derive(Debug)]
struct Point {
    x: f64,
    y: f64,
}

fn main() {
    let p = Point { x: 3.0, y: 4.0 };
    println!("{:?}", p);
}
```

```
Point { x: 3.0, y: 4.0 }
```

One line, `#[derive(Debug)]`, and `Point` is printable with `{:?}`. The output shows the type name and every field with its value, which is exactly what you want when debugging: a faithful, unambiguous dump of what's actually in the value. This is `{:?}` finally paying off the promise lesson [4.11](https://learnrust.net/chapter-4/tuples-and-the-unit-type/) made, now for your own types.

An **attribute** is the `#[...]` syntax: an instruction to the compiler attached to the item below it. You've seen one before in passing (`#[test]` was teased in lesson [3.6](https://learnrust.net/chapter-3/finding-issues-early/)). `derive` is the attribute that asks the compiler to generate code.

## Pretty-printing with {:#?}

For a struct with more than a couple of fields, the one-line form gets hard to read. Add the `#` flag, giving `{:#?}`, for the pretty-printed, multi-line version:

```rust
#[derive(Debug)]
struct Config {
    width: u32,
    height: u32,
    title: String,
}

fn main() {
    let c = Config {
        width: 1920,
        height: 1080,
        title: String::from("home"),
    };
    println!("{:#?}", c);
}
```

```
Config {
    width: 1920,
    height: 1080,
    title: "home",
}
```

Same information, one field per line, indented. Reach for `{:#?}` when you're eyeballing a big value, `{:?}` when you want it compact. Both come from the single `#[derive(Debug)]`.

> **Tip**
>
> The `dbg!` macro from lesson [3.4](https://learnrust.net/chapter-3/print-debugging/) uses this same `Debug` machinery. Once a struct derives `Debug`, you can wrap any expression involving it in `dbg!(...)` and get the file, line, and a pretty-printed value on stderr. Deriving `Debug` on basically every struct you write is standard practice precisely because it unlocks both `{:?}` and `dbg!`.

## What derive actually does

`#[derive(Debug)]` is the compiler writing boilerplate so you don't have to. "Print this struct by showing its name and fields" is mechanical: given the definition, there's an obvious correct implementation, and writing it by hand for every struct would be tedious and error-prone. So the compiler offers to write it, and `derive` is how you accept.

`Debug` is one of several behaviors the compiler can derive. You met `Default` last lesson (`#[derive(Default)]`); others you'll meet soon include `Clone` (the lesson [8.7](https://learnrust.net/chapter-8/clone/) deep-copy, derivable so you don't hand-write it), `Copy`, and `PartialEq` (which makes `==` work on your type). You can ask for several at once:

```rust
#[derive(Debug, Clone, Default)]
struct Point {
    x: f64,
    y: f64,
}
```

Each name in the list is a distinct piece of behavior, called a **trait**, that the compiler now implements for your type. That word is chapter 16's whole story, and `derive` will make complete sense once you've seen what a trait is and how you'd implement one by hand. For this chapter, the working understanding is enough: `derive` is a request for the compiler to write standard, obvious code on your behalf, and `Debug` is the one you'll reach for constantly.

> **Key insight**
>
> `{}` is for your users; `{:?}` is for you. `Display` (`{}`) is a deliberate, human-facing presentation you must write yourself, because only you know how a `Point` should read in a sentence. `Debug` (`{:?}`) is a faithful structural dump the compiler can generate, because there's an obvious right answer. That's why one is derivable and the other isn't.

## Quiz time

**Question #1**

This program is refused. What's the one-line fix?

```rust
struct Temperature {
    celsius: f64,
}

fn main() {
    let t = Temperature { celsius: 21.5 };
    println!("{:?}", t);
}
```

<details class="solution">
<summary>Show solution</summary>

`Temperature` doesn't implement `Debug`, so `{:?}` is unavailable (E0277). Add `#[derive(Debug)]` above the struct. Then it prints `Temperature { celsius: 21.5 }`.

</details>

**Question #2**

What's the difference between `{}` and `{:?}`, and why can the compiler derive one but not the other?

<details class="solution">
<summary>Show solution</summary>

`{}` is `Display`, human-facing output you must define yourself because the language can't guess how your type should read in prose. `{:?}` is `Debug`, a programmer-facing structural dump the compiler can generate automatically because "show the type name and fields" has an obvious correct form. So `Debug` is derivable; `Display` is not.

</details>

**Question #3**

What does the `#` add in `{:#?}` versus `{:?}`?

<details class="solution">
<summary>Show solution</summary>

The `#` selects the pretty-printed form: each field on its own indented line, instead of the compact single-line `{:?}`. Same data and same derive, just laid out for readability when the value is large.

</details>

Deriving behavior is a hint of chapter 16, dropped here because you'll want `Debug` immediately. Next lesson returns to ownership: structs *own* their fields, which has consequences for moves, and storing a reference in a struct opens a door we'll keep shut until chapter 17.

## Sitemap

See the full [sitemap](https://learnrust.net/sitemap.md) for all pages.
