rustbook-learning-guide 0.1.0

A comprehensive Rust learning guide with practical examples covering ownership, traits, polymorphism, and more
Documentation
//! # Polymorphism in Rust
//! 
//! This module demonstrates various forms of polymorphism in Rust, including:
//! - Trait objects for dynamic dispatch
//! - Generics for static dispatch
//! - Enum-based polymorphism
//! - Function pointers and closures

use std::fmt::Display;

/// A trait for drawable objects
pub trait Drawable {
    fn draw(&self);
    fn area(&self) -> f64;
}

/// Rectangle struct
pub struct Rectangle {
    width: f64,
    height: f64,
}

impl Rectangle {
    pub fn new(width: f64, height: f64) -> Self {
        Rectangle { width, height }
    }
}

impl Drawable for Rectangle {
    fn draw(&self) {
        println!("Drawing a rectangle {}x{}", self.width, self.height);
    }
    
    fn area(&self) -> f64 {
        self.width * self.height
    }
}

/// Circle struct
pub struct Circle {
    radius: f64,
}

impl Circle {
    pub fn new(radius: f64) -> Self {
        Circle { radius }
    }
}

impl Drawable for Circle {
    fn draw(&self) {
        println!("Drawing a circle with radius {}", self.radius);
    }
    
    fn area(&self) -> f64 {
        std::f64::consts::PI * self.radius * self.radius
    }
}

/// Triangle struct
pub struct Triangle {
    base: f64,
    height: f64,
}

impl Triangle {
    pub fn new(base: f64, height: f64) -> Self {
        Triangle { base, height }
    }
}

impl Drawable for Triangle {
    fn draw(&self) {
        println!("Drawing a triangle with base {} and height {}", self.base, self.height);
    }
    
    fn area(&self) -> f64 {
        0.5 * self.base * self.height
    }
}

/// Demonstrates polymorphism examples
pub fn polymorphism_examples() {
    println!("\n🎭 Polymorphism Examples");
    println!("{}", "=".repeat(25));
    
    trait_object_polymorphism();
    generic_polymorphism();
    enum_polymorphism();
    closure_polymorphism();
    function_pointer_polymorphism();
    advanced_trait_patterns();
}

/// Demonstrates trait objects for dynamic dispatch
fn trait_object_polymorphism() {
    println!("\n🎯 Trait Object Polymorphism (Dynamic Dispatch)");
    println!("{}", "-".repeat(35));
    
    // Vector of trait objects
    let shapes: Vec<Box<dyn Drawable>> = vec![
        Box::new(Rectangle::new(10.0, 5.0)),
        Box::new(Circle::new(3.0)),
        Box::new(Triangle::new(8.0, 6.0)),
    ];
    
    println!("Drawing all shapes:");
    for shape in &shapes {
        shape.draw();
        println!("Area: {:.2}", shape.area());
    }
    
    // Using trait objects as function parameters
    draw_shape(&Rectangle::new(15.0, 10.0));
    draw_shape(&Circle::new(5.0));
}

fn draw_shape(shape: &dyn Drawable) {
    println!("Generic draw function:");
    shape.draw();
    println!("Area: {:.2}", shape.area());
}

/// Demonstrates generics for static dispatch
fn generic_polymorphism() {
    println!("\n⚡ Generic Polymorphism (Static Dispatch)");
    println!("{}", "-".repeat(40));
    
    let rect = Rectangle::new(12.0, 8.0);
    let circle = Circle::new(4.0);
    
    // Generic function calls - resolved at compile time
    draw_generic(&rect);
    draw_generic(&circle);
    
    // Generic function with multiple trait bounds
    print_and_draw(&rect);
    print_and_draw(&circle);
}

fn draw_generic<T: Drawable>(shape: &T) {
    println!("Generic function (compile-time dispatch):");
    shape.draw();
    println!("Area: {:.2}", shape.area());
}

fn print_and_draw<T: Drawable + std::fmt::Debug>(shape: &T) {
    println!("Shape details: {:?}", shape);
    shape.draw();
}

// Add Debug trait implementations
impl std::fmt::Debug for Rectangle {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Rectangle {{ width: {}, height: {} }}", self.width, self.height)
    }
}

impl std::fmt::Debug for Circle {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Circle {{ radius: {} }}", self.radius)
    }
}

impl std::fmt::Debug for Triangle {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Triangle {{ base: {}, height: {} }}", self.base, self.height)
    }
}

/// Demonstrates enum-based polymorphism
fn enum_polymorphism() {
    println!("\n🔄 Enum-based Polymorphism");
    println!("{}", "-".repeat(25));
    
    #[derive(Debug)]
    enum Shape {
        Rectangle { width: f64, height: f64 },
        Circle { radius: f64 },
        Triangle { base: f64, height: f64 },
    }
    
    impl Shape {
        fn draw(&self) {
            match self {
                Shape::Rectangle { width, height } => {
                    println!("Drawing rectangle {}x{}", width, height);
                }
                Shape::Circle { radius } => {
                    println!("Drawing circle with radius {}", radius);
                }
                Shape::Triangle { base, height } => {
                    println!("Drawing triangle with base {} and height {}", base, height);
                }
            }
        }
        
        fn area(&self) -> f64 {
            match self {
                Shape::Rectangle { width, height } => width * height,
                Shape::Circle { radius } => std::f64::consts::PI * radius * radius,
                Shape::Triangle { base, height } => 0.5 * base * height,
            }
        }
    }
    
    let shapes = vec![
        Shape::Rectangle { width: 10.0, height: 5.0 },
        Shape::Circle { radius: 3.0 },
        Shape::Triangle { base: 8.0, height: 6.0 },
    ];
    
    for shape in &shapes {
        shape.draw();
        println!("Area: {:.2}", shape.area());
        println!("Debug: {:?}", shape);
        println!();
    }
}

/// Demonstrates closure polymorphism
fn closure_polymorphism() {
    println!("\n🔧 Closure Polymorphism");
    println!("{}", "-".repeat(25));
    
    // Different closures with same signature
    let add = |x: i32, y: i32| x + y;
    let multiply = |x: i32, y: i32| x * y;
    let subtract = |x: i32, y: i32| x - y;
    
    // Function that accepts any closure with the right signature
    fn apply_operation<F>(x: i32, y: i32, op: F) -> i32 
    where 
        F: Fn(i32, i32) -> i32 
    {
        op(x, y)
    }
    
    println!("5 + 3 = {}", apply_operation(5, 3, add));
    println!("5 * 3 = {}", apply_operation(5, 3, multiply));
    println!("5 - 3 = {}", apply_operation(5, 3, subtract));
    
    // Closure that captures environment
    let multiplier = 10;
    let scale = |x: i32| x * multiplier;
    println!("Scaling 5 by {}: {}", multiplier, scale(5));
}

/// Demonstrates function pointer polymorphism
fn function_pointer_polymorphism() {
    println!("\n📍 Function Pointer Polymorphism");
    println!("{}", "-".repeat(25));
    
    fn add(x: i32, y: i32) -> i32 { x + y }
    fn multiply(x: i32, y: i32) -> i32 { x * y }
    
    // Function that accepts function pointers
    fn execute_operation(x: i32, y: i32, op: fn(i32, i32) -> i32) -> i32 {
        op(x, y)
    }
    
    println!("Using function pointers:");
    println!("5 + 3 = {}", execute_operation(5, 3, add));
    println!("5 * 3 = {}", execute_operation(5, 3, multiply));
    
    // Array of function pointers
    let operations: [fn(i32, i32) -> i32; 2] = [add, multiply];
    for (i, op) in operations.iter().enumerate() {
        println!("Operation {}: 4, 7 = {}", i, op(4, 7));
    }
}

/// Demonstrates advanced trait patterns
fn advanced_trait_patterns() {
    println!("\n🚀 Advanced Trait Patterns");
    println!("{}", "-".repeat(40));
    
    // Trait with associated types
    trait Iterator2 {
        type Item;
        fn next(&mut self) -> Option<Self::Item>;
    }
    
    // Trait with default implementations
    trait Greet {
        fn name(&self) -> &str;
        
        fn greet(&self) -> String {
            format!("Hello, {}!", self.name())
        }
        
        fn formal_greet(&self) -> String {
            format!("Good day, {}.", self.name())
        }
    }
    
    struct Person {
        name: String,
    }
    
    impl Greet for Person {
        fn name(&self) -> &str {
            &self.name
        }
        
        // Override default implementation
        fn greet(&self) -> String {
            format!("Hey there, {}!", self.name())
        }
    }
    
    let person = Person { name: "Alice".to_string() };
    println!("{}", person.greet());
    println!("{}", person.formal_greet());
    
    // Trait bounds in where clauses
    fn complex_function<T, U>(_t: T, _u: U) 
    where 
        T: Display + Clone,
        U: Clone + std::fmt::Debug,
    {
        println!("Complex function with multiple trait bounds");
    }
    
    complex_function("hello", 42);
}