Reputation: 5405
Point
and Vec2
are defined with the same variable and exactly the same constructor function:
pub struct Point {
pub x: f32,
pub y: f32,
}
pub struct Vec2 {
pub x: f32,
pub y: f32,
}
impl Point {
pub fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
}
impl Vec2 {
pub fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
}
Is it possible to define a trait to implement the constructor function?
So far I found it only possible to define the interface as the internal variables are not known:
pub trait TwoDimensional {
fn new(x: f32, y: f32) -> Self;
}
Upvotes: 1
Views: 1667
Reputation: 10156
You can certainly define such a trait, and implement it for your 2 structs, but you will have to write the implementation twice. Even though traits can provide default implementations for functions, the following won't work:
trait TwoDimensional {
fn new(x: f32, y: f32) -> Self {
Self {
x,
y,
}
}
}
The reason why is fairly simple. What happens if you implement this trait for i32
or ()
or an enum
?
Traits fundamentally don't have information about the underlying data structure that implements them. Rust does not support OOP, and trying to force it often leads to ugly, unidiomatic and less performant code.
If however, you have a bunch of structs and want to essentially "write the same impl
multiple times without copy/pasting", a macro might be useful. This pattern is common in the standard library, where, for example, there are certain functions that are implemented for all integer types. For example:
macro_rules! impl_constructor {
($name:ty) => {
impl $name {
pub fn new(x: f32, y: f32) -> Self {
Self {
x, y
}
}
}
}
}
impl_constructor!(Point);
impl_constructor!(Vec2);
These macros expand at compile time, so if you do something invalid (e.g. impl_constructor!(i32)
, you'll get a compilation error, since the macro expansion woudl contain i32 { x, y }
.
Personally I only use a macro when there is really a large number of types that need an implementation. This is just personal preference however, there is no runtime difference between a hand-written and a macro-generated impl
block.
Upvotes: 6