rustbook_learning_guide/
polymorphism.rs

1//! # Polymorphism in Rust
2//! 
3//! This module demonstrates various forms of polymorphism in Rust, including:
4//! - Trait objects for dynamic dispatch
5//! - Generics for static dispatch
6//! - Enum-based polymorphism
7//! - Function pointers and closures
8
9use std::fmt::Display;
10
11/// A trait for drawable objects
12pub trait Drawable {
13    fn draw(&self);
14    fn area(&self) -> f64;
15}
16
17/// Rectangle struct
18pub struct Rectangle {
19    width: f64,
20    height: f64,
21}
22
23impl Rectangle {
24    pub fn new(width: f64, height: f64) -> Self {
25        Rectangle { width, height }
26    }
27}
28
29impl Drawable for Rectangle {
30    fn draw(&self) {
31        println!("Drawing a rectangle {}x{}", self.width, self.height);
32    }
33    
34    fn area(&self) -> f64 {
35        self.width * self.height
36    }
37}
38
39/// Circle struct
40pub struct Circle {
41    radius: f64,
42}
43
44impl Circle {
45    pub fn new(radius: f64) -> Self {
46        Circle { radius }
47    }
48}
49
50impl Drawable for Circle {
51    fn draw(&self) {
52        println!("Drawing a circle with radius {}", self.radius);
53    }
54    
55    fn area(&self) -> f64 {
56        std::f64::consts::PI * self.radius * self.radius
57    }
58}
59
60/// Triangle struct
61pub struct Triangle {
62    base: f64,
63    height: f64,
64}
65
66impl Triangle {
67    pub fn new(base: f64, height: f64) -> Self {
68        Triangle { base, height }
69    }
70}
71
72impl Drawable for Triangle {
73    fn draw(&self) {
74        println!("Drawing a triangle with base {} and height {}", self.base, self.height);
75    }
76    
77    fn area(&self) -> f64 {
78        0.5 * self.base * self.height
79    }
80}
81
82/// Demonstrates polymorphism examples
83pub fn polymorphism_examples() {
84    println!("\nšŸŽ­ Polymorphism Examples");
85    println!("{}", "=".repeat(25));
86    
87    trait_object_polymorphism();
88    generic_polymorphism();
89    enum_polymorphism();
90    closure_polymorphism();
91    function_pointer_polymorphism();
92    advanced_trait_patterns();
93}
94
95/// Demonstrates trait objects for dynamic dispatch
96fn trait_object_polymorphism() {
97    println!("\nšŸŽÆ Trait Object Polymorphism (Dynamic Dispatch)");
98    println!("{}", "-".repeat(35));
99    
100    // Vector of trait objects
101    let shapes: Vec<Box<dyn Drawable>> = vec![
102        Box::new(Rectangle::new(10.0, 5.0)),
103        Box::new(Circle::new(3.0)),
104        Box::new(Triangle::new(8.0, 6.0)),
105    ];
106    
107    println!("Drawing all shapes:");
108    for shape in &shapes {
109        shape.draw();
110        println!("Area: {:.2}", shape.area());
111    }
112    
113    // Using trait objects as function parameters
114    draw_shape(&Rectangle::new(15.0, 10.0));
115    draw_shape(&Circle::new(5.0));
116}
117
118fn draw_shape(shape: &dyn Drawable) {
119    println!("Generic draw function:");
120    shape.draw();
121    println!("Area: {:.2}", shape.area());
122}
123
124/// Demonstrates generics for static dispatch
125fn generic_polymorphism() {
126    println!("\n⚔ Generic Polymorphism (Static Dispatch)");
127    println!("{}", "-".repeat(40));
128    
129    let rect = Rectangle::new(12.0, 8.0);
130    let circle = Circle::new(4.0);
131    
132    // Generic function calls - resolved at compile time
133    draw_generic(&rect);
134    draw_generic(&circle);
135    
136    // Generic function with multiple trait bounds
137    print_and_draw(&rect);
138    print_and_draw(&circle);
139}
140
141fn draw_generic<T: Drawable>(shape: &T) {
142    println!("Generic function (compile-time dispatch):");
143    shape.draw();
144    println!("Area: {:.2}", shape.area());
145}
146
147fn print_and_draw<T: Drawable + std::fmt::Debug>(shape: &T) {
148    println!("Shape details: {:?}", shape);
149    shape.draw();
150}
151
152// Add Debug trait implementations
153impl std::fmt::Debug for Rectangle {
154    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155        write!(f, "Rectangle {{ width: {}, height: {} }}", self.width, self.height)
156    }
157}
158
159impl std::fmt::Debug for Circle {
160    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161        write!(f, "Circle {{ radius: {} }}", self.radius)
162    }
163}
164
165impl std::fmt::Debug for Triangle {
166    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167        write!(f, "Triangle {{ base: {}, height: {} }}", self.base, self.height)
168    }
169}
170
171/// Demonstrates enum-based polymorphism
172fn enum_polymorphism() {
173    println!("\nšŸ”„ Enum-based Polymorphism");
174    println!("{}", "-".repeat(25));
175    
176    #[derive(Debug)]
177    enum Shape {
178        Rectangle { width: f64, height: f64 },
179        Circle { radius: f64 },
180        Triangle { base: f64, height: f64 },
181    }
182    
183    impl Shape {
184        fn draw(&self) {
185            match self {
186                Shape::Rectangle { width, height } => {
187                    println!("Drawing rectangle {}x{}", width, height);
188                }
189                Shape::Circle { radius } => {
190                    println!("Drawing circle with radius {}", radius);
191                }
192                Shape::Triangle { base, height } => {
193                    println!("Drawing triangle with base {} and height {}", base, height);
194                }
195            }
196        }
197        
198        fn area(&self) -> f64 {
199            match self {
200                Shape::Rectangle { width, height } => width * height,
201                Shape::Circle { radius } => std::f64::consts::PI * radius * radius,
202                Shape::Triangle { base, height } => 0.5 * base * height,
203            }
204        }
205    }
206    
207    let shapes = vec![
208        Shape::Rectangle { width: 10.0, height: 5.0 },
209        Shape::Circle { radius: 3.0 },
210        Shape::Triangle { base: 8.0, height: 6.0 },
211    ];
212    
213    for shape in &shapes {
214        shape.draw();
215        println!("Area: {:.2}", shape.area());
216        println!("Debug: {:?}", shape);
217        println!();
218    }
219}
220
221/// Demonstrates closure polymorphism
222fn closure_polymorphism() {
223    println!("\nšŸ”§ Closure Polymorphism");
224    println!("{}", "-".repeat(25));
225    
226    // Different closures with same signature
227    let add = |x: i32, y: i32| x + y;
228    let multiply = |x: i32, y: i32| x * y;
229    let subtract = |x: i32, y: i32| x - y;
230    
231    // Function that accepts any closure with the right signature
232    fn apply_operation<F>(x: i32, y: i32, op: F) -> i32 
233    where 
234        F: Fn(i32, i32) -> i32 
235    {
236        op(x, y)
237    }
238    
239    println!("5 + 3 = {}", apply_operation(5, 3, add));
240    println!("5 * 3 = {}", apply_operation(5, 3, multiply));
241    println!("5 - 3 = {}", apply_operation(5, 3, subtract));
242    
243    // Closure that captures environment
244    let multiplier = 10;
245    let scale = |x: i32| x * multiplier;
246    println!("Scaling 5 by {}: {}", multiplier, scale(5));
247}
248
249/// Demonstrates function pointer polymorphism
250fn function_pointer_polymorphism() {
251    println!("\nšŸ“ Function Pointer Polymorphism");
252    println!("{}", "-".repeat(25));
253    
254    fn add(x: i32, y: i32) -> i32 { x + y }
255    fn multiply(x: i32, y: i32) -> i32 { x * y }
256    
257    // Function that accepts function pointers
258    fn execute_operation(x: i32, y: i32, op: fn(i32, i32) -> i32) -> i32 {
259        op(x, y)
260    }
261    
262    println!("Using function pointers:");
263    println!("5 + 3 = {}", execute_operation(5, 3, add));
264    println!("5 * 3 = {}", execute_operation(5, 3, multiply));
265    
266    // Array of function pointers
267    let operations: [fn(i32, i32) -> i32; 2] = [add, multiply];
268    for (i, op) in operations.iter().enumerate() {
269        println!("Operation {}: 4, 7 = {}", i, op(4, 7));
270    }
271}
272
273/// Demonstrates advanced trait patterns
274fn advanced_trait_patterns() {
275    println!("\nšŸš€ Advanced Trait Patterns");
276    println!("{}", "-".repeat(40));
277    
278    // Trait with associated types
279    trait Iterator2 {
280        type Item;
281        fn next(&mut self) -> Option<Self::Item>;
282    }
283    
284    // Trait with default implementations
285    trait Greet {
286        fn name(&self) -> &str;
287        
288        fn greet(&self) -> String {
289            format!("Hello, {}!", self.name())
290        }
291        
292        fn formal_greet(&self) -> String {
293            format!("Good day, {}.", self.name())
294        }
295    }
296    
297    struct Person {
298        name: String,
299    }
300    
301    impl Greet for Person {
302        fn name(&self) -> &str {
303            &self.name
304        }
305        
306        // Override default implementation
307        fn greet(&self) -> String {
308            format!("Hey there, {}!", self.name())
309        }
310    }
311    
312    let person = Person { name: "Alice".to_string() };
313    println!("{}", person.greet());
314    println!("{}", person.formal_greet());
315    
316    // Trait bounds in where clauses
317    fn complex_function<T, U>(_t: T, _u: U) 
318    where 
319        T: Display + Clone,
320        U: Clone + std::fmt::Debug,
321    {
322        println!("Complex function with multiple trait bounds");
323    }
324    
325    complex_function("hello", 42);
326}
327