Step 4 of 6
Printing structs with Debug
Try to print a struct with {} and Rust refuses:
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 1, y: 2 };
println!("{}", p);
}
error[E0277]: `Point` doesn't implement `std::fmt::Display`
{} uses Display, the "pretty, for end users" format. Rust doesn't guess how your type should look to users ((1, 2)? x=1 y=2?), so you'd have to write that yourself, which you'll learn in the traits module. {:?} uses Debug, the "for programmers" format, and for that Rust can write the code for you.
#[derive(Debug)]
#[derive(Debug)]
struct Item {
name: String,
price_cents: u32,
in_stock: bool,
}
fn main() {
let item = Item {
name: String::from("Tea"),
price_cents: 450,
in_stock: true,
};
println!("{:?}", item);
println!("{:#?}", item);
if item.in_stock {
println!("{} costs {} cents", item.name, item.price_cents);
}
}
Item { name: "Tea", price_cents: 450, in_stock: true }
Item {
name: "Tea",
price_cents: 450,
in_stock: true,
}
Tea costs 450 cents
#[derive(Debug)]is an attribute: a note to the compiler written above an item. derive asks the compiler to generate code for you, here the Debug formatting. (Debug is a trait, a named ability a type can have; the traits module covers them properly.){:?}prints everything on one line.{:#?}pretty-prints, one field per line, which is much easier to read for big or nested structs.- Nearly every struct in real code derives
Debug. It costs nothing until you use it, and it makes logging and debugging painless.
dbg!
dbg!(expression) prints the file, the line, the expression and its value, then returns the value, so you can wrap it around something in the middle of your code:
#[derive(Debug)]
struct Item {
name: String,
price_cents: u32,
}
fn main() {
let price_cents = dbg!(150 * 3);
let item = Item { name: String::from("Tea"), price_cents };
dbg!(&item);
println!("{} costs {}", item.name, item.price_cents);
}
Tea costs 450
The dbg! lines go to standard error (stderr), not standard output, so they don't mix with the program's real output (and the tests on this site ignore them). In a terminal you'd see:
[src/main.rs:8:23] 150 * 3 = 450
[src/main.rs:10:5] &item = Item {
name: "Tea",
price_cents: 450,
}
Pass a reference (dbg!(&item)): dbg!(item) would move item into the macro. dbg! is for debugging sessions; remove it before you commit (many teams turn on clippy's dbg_macro lint to catch leftovers).
Comparing with ==
== doesn't work on your struct either until you derive PartialEq, which compares field by field. You can derive several things at once: #[derive(Debug, PartialEq)]. assert_eq! needs both: PartialEq to compare and Debug to show the two values when they differ.
#[derive(Debug, PartialEq)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let a = Point { x: 1, y: 2 };
let b = Point { x: 1, y: 2 };
println!("{}", a == b);
println!("{}", a == Point { x: 2, y: 1 });
}
true
false
Common mistakes
{:?}without the derive:error[E0277]: `Point` doesn't implement `Debug`. The error's help line tells you to add#[derive(Debug)].==without PartialEq:error[E0369]: binary operation `==` cannot be applied to type `Point`.- A field only used in
{:?}: the compiler warnsfield `name` is never read, because derived Debug output doesn't count as using a field. Real code reads its fields; if it doesn't, the field may not be needed.
Your task
Fill in the blanks: derive the trait that {:?} needs, and print p with it. The program should print:
sum: 1
Point { x: 3, y: -2 }
Challenge 2
Add one derive line so that Item can be pretty-printed and compared with ==. Then print a with the pretty Debug format and print whether a == b, so the output is exactly:
Item {
name: "bolt",
qty: 40,
}
same: true
Challenge 3
Write two functions for 2D points:
fn moved(p: Point, dx: i32, dy: i32) -> Point: the point shifted bydxanddy.fn midpoint(a: &Point, b: &Point) -> Point: the point halfway between, using integer division ((1 + 4) / 2is2).
The hidden tests compare whole points with assert_eq!, so Point needs the right derives. Add them yourself.
Previous: Building structs with shorthand and update syntax Next: Tuple structs, newtypes and unit structs