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 })
}