Rust

Lesson 06

Traits and generic contracts

Use trait bounds to name the behavior a generic function needs instead of tying code to one concrete type.

Good Code

src/review_export.rs
use std::fmt::Write;

pub fn append_review_line<W: Write>(writer: &mut W, review: &Review) -> std::fmt::Result {
    // The function asks only for the ability to receive formatted text.
    writeln!(writer, "{}:{}", review.id, review.title)
}

Bad Code

review_export.rs
pub fn append_review_line(buffer: &mut String, review: &Review) {
    // Concrete String forces callers to allocate even when another writer fits.
    buffer.push_str(&format!("{}:{}\n", review.id, review.title));
}

Review Notes

What to review

Good Code

The good version depends on Write, so tests can pass a String, production code can pass another formatter, and errors stay visible.

Bad Code

The bad version hard-codes String and uses format! before appending. Callers with an existing writer cannot reuse the function without extra allocation.

Takeaways

  • A Rust generic should declare the smallest trait contract needed by the function body.