I'm new to Rust and coming from C++ background. Trying to design an interface, I'm undecided between 2 approaches:
struct Handler {
name: String,
invoke: fn()
}
struct MyHandler1;
impl MyHandler1 {
fn new() -> Handler {
name: String::from("myhandler1"),
invoke: || { println!("hello") }
}
}
(...)
const MY_HANDLERS: &[Handler] = &[MyHandler1::new(), MyHandler2::new()];
and
trait Handler {
fn name(&self) -> String;
fn invoke(&self);
}
struct MyHandler1;
impl Handler for MyHandler1 {
fn name(&self) -> String { "myhandler1".to_string() }
fn invoke(&self) {
println!("hello");
}
}
(...)
// can't have const fn in traits so box'em up inside main...
let handlers: Vec<Box<dyn Handler>> = vec![Box::new(MyHandler1], Box::new(MyHandler2)];
I'm leaning towards the former example, but I can't shake the feeling that it's coming from a deeply ingrained C++ way of thinking, having all the functions and members nicely stacked up inside classes and simulating type erasure by the new
function that generates a "base class" instead of trying to get used to thinking in Rust.
It feels like Rust encourages using functions instead of objects (traits instead of inheritance). Is there an established good practice in Rust community to this end? Are both approaches considered OK and just a matter of preference? Or are there alternatives that you use to achieve this kind of design? (Please ignore trivial syntax errors)