📖 Scenario: You are building a small Rust program that works with different types of shapes. Each shape can calculate its area. You want to write a function that can accept any shape, as long as it can calculate its area.
🎯 Goal: Create a trait called Shape with a method area. Then write a function print_area that accepts any type implementing the Shape trait and prints its area.
📋 What You'll Learn
Create a trait named Shape with a method area that returns an f64.
Create a struct Circle with a field radius of type f64.
Implement the Shape trait for Circle.
Create a function print_area that accepts a generic parameter with a trait bound Shape.
Call print_area with a Circle instance and print the area.
💡 Why This Matters
🌍 Real World
Traits let you write flexible code that works with many types sharing common behavior, like shapes calculating area.
💼 Career
Understanding trait bounds is essential for writing reusable and safe Rust code, a key skill for Rust developers.
Progress0 / 4 steps
1
Create the Circle struct
Create a struct called Circle with one field radius of type f64.
Rust
Hint
Use struct Circle { radius: f64 } to define the shape.
2
Create the Shape trait
Create a trait called Shape with a method area that returns an f64.
Rust
Hint
Use trait Shape { fn area(&self) -> f64; } to define the trait.
3
Implement Shape for Circle
Implement the Shape trait for Circle. The area method should return 3.14 * radius * radius.
Rust
Hint
Use impl Shape for Circle { fn area(&self) -> f64 { 3.14 * self.radius * self.radius } }.
4
Write print_area function and call it
Write a function called print_area that accepts a generic parameter T with a trait bound Shape. Inside, print the area using println!("Area: {}", shape.area()). Then create a Circle with radius 5.0 and call print_area with it.
Rust
Hint
Use fn print_area(shape: &T) and call print_area(&circle) in main.
Practice
(1/5)
1. What does a trait bound like T: Display mean in Rust?
easy
A. The generic type T cannot implement the Display trait.
B. The generic type T must implement the Display trait.
C. The function only accepts the Display type, not generics.
D. The trait Display is optional for T.
Solution
Step 1: Understand trait bounds syntax
In Rust, T: TraitName means the generic type T must implement the trait TraitName.
Step 2: Apply to T: Display
This means T must implement the Display trait to be used where this bound is required.
Final Answer:
The generic type T must implement the Display trait. -> Option B
Quick Check:
Trait bound T: Display means T implements Display [OK]
Hint: Trait bounds require the type to implement the trait [OK]
Common Mistakes:
Thinking trait bounds exclude the trait
Confusing trait bounds with type restrictions
Assuming trait bounds are optional
2. Which of the following is the correct syntax to add a trait bound for a generic type T that must implement the Clone trait in a function?
easy
A. fn example(value: T) {}
B. fn example(value: T) {}
C. fn example(value: T) {}
D. fn example(value: T) {}
Solution
Step 1: Recall trait bound syntax
The correct syntax to add a trait bound is T: TraitName, with a colon and capitalized trait name.
Step 2: Check each option
fn example(value: T) {} uses T: Clone which is correct. fn example(value: T) {} misses the colon. fn example(value: T) {} misuses where without proper syntax. fn example(value: T) {} uses lowercase clone, which is incorrect.
Final Answer:
fn example<T: Clone>(value: T) {} -> Option D
Quick Check:
Trait bound syntax uses colon and capitalized trait [OK]
Hint: Use colon and capitalized trait for bounds (T: Trait) [OK]
B. Incorrect macro usage, should use {} instead of {:?}.
C. Function should return a value, missing return type.
D. No error, code compiles and runs fine.
Solution
Step 1: Understand the use of {:?} in println!
The {:?} format specifier requires the type to implement the Debug trait.
Step 2: Check function signature
The function print_debug has no trait bound on T, so the compiler cannot guarantee T implements Debug.
Final Answer:
Missing trait bound T: Debug for value. -> Option A
Quick Check:
Using {:?} requires T: Debug trait bound [OK]
Hint: Add trait bound when using {:?} formatting [OK]
Common Mistakes:
Forgetting to add T: Debug bound
Using {:?} without Debug trait
Assuming all types implement Debug by default
5. You want to write a generic function that accepts any type T which implements both Clone and Debug traits. Which is the correct way to write the function signature?
hard
A. fn process(value: T) {}
B. fn process(value: T) {}
C. fn process<T>(value: T) where T: Clone + Debug {}
D. }{ )T :eulav(>gubeD + enolC :T
Solution
Step 1: Understand trait bounds syntax
You can specify multiple trait bounds using either T: Trait1 + Trait2 or a where clause like where T: Trait1 + Trait2.
Step 2: Analyze options
fn process(value: T) {} uses T: Clone + Debug which is correct. fn process(value: T) {} incorrectly separates traits with a comma. fn process<T>(value: T) where T: Clone + Debug {} uses a valid where clause. fn process(value: T) {} states "Both A and C are correct" which is not an option here, so only C is correct.
Final Answer:
fn process<T>(value: T) where T: Clone + Debug {} -> Option C
Quick Check:
Multiple trait bounds can be combined with + or where clause [OK]
Hint: Use + or where clause to combine trait bounds [OK]
Common Mistakes:
Separating trait bounds with commas instead of +
Confusing where clause syntax
Using only one trait bound when multiple needed
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.