use std::fmt::Display;
pub trait Drawable {
fn draw(&self);
fn area(&self) -> f64;
}
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
}
}
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
}
}
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
}
}
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();
}
fn trait_object_polymorphism() {
println!("\n🎯 Trait Object Polymorphism (Dynamic Dispatch)");
println!("{}", "-".repeat(35));
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());
}
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());
}
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);
draw_generic(&rect);
draw_generic(&circle);
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();
}
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)
}
}
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!();
}
}
fn closure_polymorphism() {
println!("\n🔧 Closure Polymorphism");
println!("{}", "-".repeat(25));
let add = |x: i32, y: i32| x + y;
let multiply = |x: i32, y: i32| x * y;
let subtract = |x: i32, y: i32| x - y;
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));
let multiplier = 10;
let scale = |x: i32| x * multiplier;
println!("Scaling 5 by {}: {}", multiplier, scale(5));
}
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 }
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));
let operations: [fn(i32, i32) -> i32; 2] = [add, multiply];
for (i, op) in operations.iter().enumerate() {
println!("Operation {}: 4, 7 = {}", i, op(4, 7));
}
}
fn advanced_trait_patterns() {
println!("\n🚀 Advanced Trait Patterns");
println!("{}", "-".repeat(40));
trait Iterator2 {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
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
}
fn greet(&self) -> String {
format!("Hey there, {}!", self.name())
}
}
let person = Person { name: "Alice".to_string() };
println!("{}", person.greet());
println!("{}", person.formal_greet());
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);
}