I have a simple trait which simply declares 2 getter methods. Let's call it MyTrait
. Each method borrows self immutably and returns some number.
The trait is exported and publicly/externally usable for any users of my lib. Within my lib, I am also a user/implementor of the trait (I have types which implement the trait). So let's say I also have defined in my lib a concrete type called MyElement
for which I would like to implement MyTrait
.
Now I can just implement it directly (impl MyTrait for MyElement
), but there's a small problem that I ran into. Basically, I would like to be able to pass any kind of reference (whether it's a value of type &MyElement
, Box<MyElement>
, Arc<MyElement>
, etc.), in addition to being able to pass an owned MyElement
, to any of my lib's functions or types that work with MyTrait
values generically. Also, by accepting either an owned value or ref, I can leave that decision up to the caller for maximum flexibility. How should I go about this?
I have come up with 3 ideas:
-
As a user of the trait, simply implement it for all of these concrete types (i.e.
MyElement
,&MyElement
,Box<MyElement>
, etc.). This is the most straightforward but feels overly-explicit, boilerplate-heavy, and not very user-friendly. It requires multiple impls for the same underlying type (i.e.MyElement
) and doesn't cover custom pointer types up front. -
Define a
MyTrait
blanket impl within the lib that definesMyTrait
. For example:
impl<T, U> MyTrait for T
where
T: Deref<Target=U>,
U: MyTrait,
Now all I'd have to do is implement MyTrait
for MyElement
.
- Just be more broad in what my generic library functions and types accept for those that accept some
T
whereT: MyTrait
. E.g. use bounds like this instead:
// ...
where
T: Borrow<U>,
U: MyTrait,
// ...
The con/issue with this is, now I have signatures which are more complex and less ergonomic to work with (and now every time I want to call a trait method of MyTrait
I need to call .borrow()
on it first). Plus, these more complex bounds/signatures will propagate to all of the other places where I want to work with some type implementing MyTrait
as well. Therefore, I have essentially decided against going this route.
I'm leaning towards just doing #2, but maybe that's a bad idea? idk what to do. idk know what's best here.
Hopefully that all makes sense. Thanks