I have a trait which can be called T. In a lot of places i currently use Rc<dyn T>.
The problem is that i wanted to add a default method to T that runs a function the needs Rc<dyn T>. But as far as i can see there is no way to cast Rc<Self> because Self is not sized in a trait. I can not make the whole project use generics, so how could i get around this?
example:
use std::rc::Rc;
trait T {
fn run_test_method(self: Rc<Self>) {
test_method(self);
}
}
struct A;
impl T for A {}
fn test_method(_rc: Rc<dyn T>) {
// do stuff with 'rc'
}
fn main() {
let a = Rc::new(A) as Rc<dyn T>;
a.run_test_method();
}
The compiler gives you multiple hints about this, and if you follow them all you will wind up with something like this, which does compile:
The
Sizedbound is required so that the cast can be performed, and the'staticbound is required because there is no lifetime ondyn Tin thetest_methodargument, which makes it implicitlydyn T + 'static.If you can't require the
'staticlifetime for some reason (because the implementors ofTcontain non-static borrows) then you can remove the'staticbound onT::run_test_methodif you indicate that thedyn Tcan have a non-static lifetime ontest_method:If you want to be able to call this method with either an
Rc<A>or anRc<dyn T>then you will have to implement this separately for both cases, because fundamentally each method does something different. One casts a (pointer to a) sized value to a trait object, and the other does not.You can accomplish this by using a helper trait that you implement for both cases. (The type names here will be a bit confusing to people who work in Rust regularly because
Tis usually a generic type, but here it's a trait.)Note the compiler allows these implementations because they don't overlap. Generic types are implicitly
Sizedunless otherwise specified, anddyn Tis!Sized-- therefore the compiler can easily prove that the sets of types that each implementation will cover are disjoint.Now, you can do this:
(Playground)