Implementing Polymorphism with Traits in Rust
Rust doesn't have traditional class-based subtyping like some object-oriented languages. Instead, it achieves similar polymorphism through its powerful trait system. This challenge will guide you through implementing a form of subtyping using traits, allowing you to define common behavior that can be implemented by different concrete types.
Problem Description
Your task is to create a system that represents a collection of "Shapes" and allows you to perform a common operation on them, such as calculating their area. You should define a trait that all shapes will implement, and then create concrete shape types (e.g., Circle, Rectangle) that adhere to this trait. This will enable you to treat different shape types uniformly through a common interface.
Key Requirements:
- Define a
ShapeTrait: This trait should have a method,area(), which returns the calculated area of the shape as af64. - Implement Concrete Shape Types: Create at least two concrete struct types:
CircleandRectangle.Circleshould store itsradius(f64).Rectangleshould store itswidthandheight(bothf64).
- Implement
Shapefor Concrete Types: Implement theShapetrait for bothCircleandRectangle, providing the correct area calculation logic for each. - Demonstrate Polymorphism: Write a function that accepts a collection of
Shapeobjects (using trait objects or generics) and iterates through them, calling thearea()method on each and printing the result.
Expected Behavior:
When given a collection containing various shapes, the program should correctly calculate and print the area for each individual shape.
Edge Cases to Consider:
- Shapes with zero dimensions (e.g., a circle with radius 0, a rectangle with zero width or height).
- Shapes with negative dimensions (you can decide how to handle this – either disallow them or treat them as zero).
Examples
Example 1:
Input: A collection containing a Circle with radius 5.0 and a Rectangle with width 4.0 and height 6.0.
Output:
Circle Area: 78.53981633974483
Rectangle Area: 24.0
Explanation: The program correctly calculates the area of the circle (π * r²) and the rectangle (width * height) and prints them with descriptive labels.
Example 2:
Input: A collection containing a Circle with radius 0.0, a Rectangle with width 10.0 and height 0.0, and a Rectangle with width 2.0 and height 3.0.
Output:
Circle Area: 0.0
Rectangle Area: 0.0
Rectangle Area: 6.0
Explanation: The program handles shapes with zero dimensions correctly, resulting in zero area for those shapes.
Constraints
- All dimensions (radius, width, height) will be non-negative
f64values. - The number of shapes in a collection will not exceed 1000.
- Calculations involving
f64should maintain standard floating-point precision.
Notes
- Think about how you will store a collection of different types that all implement the same trait. Rust's
Box<dyn Trait>(trait objects) or generic functions can be used here. - Remember the formula for the area of a circle: π * r².
- Remember the formula for the area of a rectangle: width * height.
- You will need to import the
std::f64::consts::PIfor the circle's area calculation.