Week 12: Generics and Traits
Session 1: Generic Types
Session 2: Traits Deep Dive
Real-world impact:
Vec<T>, Option<T>, Result<T, E>)Industry examples:
Without generics, you need duplicate code:
Problem: Same logic, different types → code duplication!
Generic functions work with multiple types:
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in list {
if item > largest {
largest = item;
}
}
largest
}
// Works with any type that can be compared!
let numbers = vec![34, 50, 25, 100, 65];
let result = largest(&numbers);
let chars = vec!['y', 'm', 'a', 'q'];
let result = largest(&chars);Key concept: T: PartialOrd is a trait bound - T must implement PartialOrd.
Define structs that work with any type:
Multiple type parameters:
You’ve been using generic enums all along:
Usage:
Methods on generic structs:
Notice: impl<T> declares the generic, then Point<T> uses it.
Traits define shared behavior:
Think of traits as: - Interfaces (Java/C#) - Protocols (Swift) - Type classes (Haskell)
Traits can provide default behavior:
pub trait Summary {
fn summarize_author(&self) -> String;
fn summarize(&self) -> String {
format!("(Read more from {}...)", self.summarize_author())
}
}
struct Tweet {
username: String,
content: String,
}
impl Summary for Tweet {
fn summarize_author(&self) -> String {
format!("@{}", self.username)
}
// summarize() uses the default implementation
}Accept any type implementing a trait:
pub fn notify(item: &impl Summary) {
println!("Breaking news! {}", item.summarize());
}
// Longer syntax (trait bound):
pub fn notify<T: Summary>(item: &T) {
println!("Breaking news! {}", item.summarize());
}
// Multiple trait bounds:
pub fn notify<T: Summary + Display>(item: &T) {
// Can call summarize() and also use {} formatting
}where ClauseMake complex trait bounds readable:
Use where when: - Multiple trait bounds - Complex generic relationships - Improves readability
Return types that implement traits:
Limitation: Can only return ONE concrete type:
Frequently used traits you should know:
Debug: Format with {:?} (derive with #[derive(Debug)])Clone: Create deep copies with .clone()Copy: Types that can be copied by just copying bitsDisplay: Format with {} (implement manually)PartialEq: Compare with == and !=Eq: Full equivalence relationPartialOrd: Compare with <, >, <=, >=Ord: Total orderingIterator: Types that can be iterated overAutomatically implement common traits:
Can derive: - Debug, Clone, Copy - PartialEq, Eq, PartialOrd, Ord - Hash, Default
Cannot derive: Display, Iterator (must implement manually)
Custom formatting for user-facing output:
Make your types iterable:
Building a generic data structure:
Design assistance: - “Help me design a generic cache data structure in Rust” - “What traits should my custom type implement for common operations?” - “Explain when to use trait bounds vs where clauses”
Implementation help: - “How do I implement the Iterator trait for my custom struct?” - “Why can’t I return different types from a function returning impl Trait?” - “Help me fix this trait bound error: [paste error]”
Code review: - “Is this the idiomatic way to use generics in Rust?” - “Should this be a generic function or use dynamic dispatch?” - “How can I make these trait bounds more readable?”
What we’ll cover:
Goal: Master Rust’s powerful trait system for polymorphism and code reuse
What you’ll build:
Stack<T> data structurepush, pop, peek, is_empty, lenDisplay trait for custom formattingIterator trait to make your stack iterableLearning goals:
Deliverable: A fully functional, well-tested generic stack!
Why these skills matter:
Generics: - Foundation of modern language features (Java, C#, TypeScript, Swift, Go) - Essential for library and framework development - Interview questions: “Design a generic data structure” - Understanding constraints and bounds
Traits/Interfaces: - Interface design skills transfer to all languages - Composition over inheritance (modern best practice) - Critical for extensible systems and plugin architectures - Type system understanding for advanced roles
Real interview questions: - “Explain the difference between generics and dynamic dispatch” - “Design an interface for [problem] - what methods would it have?” - “How would you make this code reusable across different types?” - “What are the tradeoffs between compile-time and runtime polymorphism?”
Generics: - Enable code reuse without sacrificing type safety - Zero-cost abstractions - no runtime overhead - Work with structs, enums, functions, and methods - Use trait bounds to constrain type parameters
Traits: - Define shared behavior across types - Enable polymorphism without inheritance - Foundation of Rust’s standard library - Can have default implementations for convenience
Together: - Generics + Traits = Powerful, reusable abstractions - Type safety at compile time - Expressive code that’s still performant - Industry-standard design patterns
Official documentation: - The Rust Book - Chapter 10: Generic Types, Traits, and Lifetimes - Rust by Example: Generics - Rust by Example: Traits - Rust Standard Library Traits
Articles and guides: - Rust Traits: A Deep Dive - Generic Associated Types - Tour of Rust’s Standard Library Traits
Tools: - Rust Playground - Test code online - docs.rs - Browse crate documentation
Week 13 topics:
Why it matters: Learn to build complete, tested, distributable applications
Focus: Final project work begins - no new lab assignments
Get help:
This week’s materials:
Lab due: Sunday, November 23, 2025, at 11:59 PM
What to do:
Remember: You’re not just learning Rust - you’re learning universal programming concepts that apply everywhere!
Good luck! 🦀
IS4010: App Development with AI