I have a trait in Rust that offers a few default implementations for its functions.
trait MyTrait {
fn do_something(&self);
fn say_hello(&self) {
println!("Hello I am default");
}
}
Some implementors extend this trait and use the provided defaults
struct MyNormalImplementor {}
impl MyTrait for MyNormalImplementor {
fn do_something(&self) {
// self.doing_some_normal_stuff();
}
}
Now I would like to have an implementor that extends the behavior of the trait, but still uses the default implementation sometimes. Of course the default implementationis more complex and I want to follow the DRY principle.
struct MySpecializedImplementor(bool)
impl MyTrait for MySpecializedImplementor {
fn do_something(&self) {
// self.doing_some_wild_stuff();
}
fn say_hello(&self) {
if self.0 {
println!("hey, I am special");
} else {
MyTrait::say_hello(self);
}
}
}
Here MyTrait::say_hello(self);
immediately calls the specialized function in an endless loop. I did not find any way to qualify the function call so that the default implementation in MyTrait
is called instead. Is there any way to achieve that, or do I have to create a proxy function (that will be in the public interface of my trait as well) for that case?
Free-standing generic function
Defer the default implementation to a free-standing generic function:
playground
Two default trait methods
Another approach could be defining two trait methods, one as a default implementation and the other which defers to the default implementation unless it is overwritten:
playground
Default associated consts
Although this is a tad more clunky, if the difference between the default and specialized implementations be reduced down to
const
values then you can use default associatedconst
trait items for your trait:playground
Call Default implementation via AsRef
If the only thing that differentiates
Special
fromNormal
is a few extra fields, and theSpecial
type can otherwise function as aNormal
then you may want to implementAsRef<Normal>
forSpecial
and call the default implementation that way:playground
Default macro implementation
As usual, if all else fails, the most brute force way to make your code DRY is to use macros:
playground