How to Return Different Types from a Function (Trait Objects vs Enums)

Use enums for known, finite return types and trait objects for dynamic dispatch over shared behaviors.

Use an enum to return different types when the set of possibilities is known and finite, or a dyn Trait object when you need dynamic dispatch over many types sharing behavior. Enums are preferred for performance and compile-time safety, while trait objects are used for flexibility when the exact type isn't known at compile time.

// Enum approach: Known, finite set of types
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(u8, u8, u8),
}

fn create_message() -> Message {
    Message::Write(String::from("hello"))
}

// Trait object approach: Dynamic dispatch for shared behavior
trait Draw {
    fn draw(&self);
}

struct Circle { radius: f64 }
struct Square { side: f64 }

impl Draw for Circle { fn draw(&self) { println!("Drawing circle"); } }
impl Draw for Square { fn draw(&self) { println!("Drawing square"); } }

fn create_shape() -> Box<dyn Draw> {
    Box::new(Circle { radius: 10.0 })
}