📖 Scenario: You are building a simple program to compare the sizes of different shapes. Each shape has a method to calculate its area. You want to write a generic function that can work with any shape that can calculate its area.
🎯 Goal: Create a generic function that accepts any shape implementing a trait with an area method, and prints the area.
📋 What You'll Learn
Define a trait called Shape with a method area that returns a f64.
Create two structs: Circle with a radius field, and Rectangle with width and height fields.
Implement the Shape trait for both Circle and Rectangle.
Write a generic function called print_area that accepts any type implementing the Shape trait and prints its area.
💡 Why This Matters
🌍 Real World
Traits and generics let you write flexible code that works with many types, like shapes, without repeating code.
💼 Career
Understanding traits and generics is essential for Rust programming jobs, especially when building reusable libraries or complex systems.
Progress0 / 4 steps
1
Define the Shape trait and structs
Define a trait called Shape with a method area that returns a f64. Then create two structs: Circle with a radius field of type f64, and Rectangle with width and height fields of type f64.
Rust
Hint
Use trait to define the trait and struct to define the shapes with their fields.
2
Implement the Shape trait for Circle and Rectangle
Implement the Shape trait for the Circle struct by defining the area method that returns the area of the circle using the formula 3.14 * radius * radius. Then implement the Shape trait for the Rectangle struct by defining the area method that returns the area using width * height.
Rust
Hint
Use impl Shape for Circle and impl Shape for Rectangle to add the area method for each.
3
Write a generic function print_area
Write a generic function called print_area that accepts a parameter shape of any type that implements the Shape trait. Inside the function, print the area of the shape using shape.area().
Rust
Hint
Use fn print_area<T: Shape>(shape: T) to define the generic function.
4
Call print_area with Circle and Rectangle
Create a Circle instance with radius 3.0 and a Rectangle instance with width 4.0 and height 5.0. Then call the print_area function with both instances to print their areas.
Rust
Hint
Remember to create the instances with the exact field values and call print_area inside fn main().
Practice
(1/5)
1. What is the main purpose of using generics with traits in Rust?
easy
A. To restrict functions to only work with primitive types
B. To allow functions or structs to work with different types that implement specific behavior
C. To enable dynamic typing in Rust
D. To automatically convert types without explicit code
Solution
Step 1: Understand generics
Generics allow writing code that works with multiple types without repeating code.
Step 2: Understand traits with generics
Traits define behavior. Using traits with generics means the generic type must implement certain behavior.
Final Answer:
To allow functions or structs to work with different types that implement specific behavior -> Option B
Quick Check:
Generics + traits = flexible code with behavior constraints [OK]
Hint: Add trait bound when using {} in println! with generics [OK]
Common Mistakes:
Ignoring missing trait bound error
Using {:?} without Debug trait bound
Assuming generic works without constraints
5. Given the following trait and struct, how can you implement a generic function compare_and_print that accepts any two items of the same type implementing both PartialOrd and Display, and prints which one is greater or if they are equal?
use std::fmt::Display;
struct Item<T> {
value: T,
}
// Implement compare_and_print here
hard
A. fn compare_and_print(a: T, b: T) {
println!("Comparing {} and {}", a, b);
}
B. fn compare_and_print<T>(a: T, b: T) where T: PartialOrd + Display {
if a >= b {
println!("{} is greater", a);
} else {
println!("{} is greater", b);
}
}
C. fn compare_and_print(a: T, b: T) {
if a > b {
println!("{} is greater", a);
} else if a < b {
println!("{} is greater", b);
} else {
println!("Both are equal: {}", a);
}
}
D. fn compare_and_print(a: T, b: T) {
if a > b {
println!("a is greater");
} else {
println!("b is greater");
}
}
Solution
Step 1: Define trait bounds for generic function
The function must require T to implement both PartialOrd (for comparison) and Display (for printing).
Step 2: Implement comparison logic with all cases
Check if a > b, print a is greater; else if a < b, print b is greater; else print both are equal.
Step 3: Verify printing uses Display trait
Use {} in println! to print values, which requires Display.
Final Answer:
fn compare_and_print<T: PartialOrd + Display>(a: T, b: T) {
if a > b {
println!("{} is greater", a);
} else if a < b {
println!("{} is greater", b);
} else {
println!("Both are equal: {}", a);
}
} -> Option C
Quick Check:
Use PartialOrd + Display for comparison and printing [OK]
Hint: Use T: PartialOrd + Display to compare and print generics [OK]
Common Mistakes:
Omitting one of the required trait bounds
Not handling equality case
Using incorrect comparison operators
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.