See here.
The function signature you wrote is impossible to implement (without leaking a newly created Rc
).
Turning concrete types into trait object types is an operation that always only can work behind exactly one level of indirection. You can turn an owned Rc<Struct>
into Rc<dyn Trait>
or a reference &Struct
into &dyn Trait
, but you cannot turn &Rc<Struct>
into &Rc<dyn Trait>
behind two levels of indirection.
This is because of where the dynamic information (vtable pointer) is stored:
Rc<Struct>: [ #address ]
| (points to)
|
+--+
|
v
[reference count] [ Struct’s field values ]
Rc<dyn Trait>: [ #address, #vtable_ptr ]
| |
| +----------------+
v |
[reference count] [ Struct’s field values ] |
|
+--------------------------------+
|
v
the vtable: [ size, destructor fn-pointer, fn-pointers for methods, … ]
So you can turn Rc<Struct>
into Rc<dyn Struct>
by adding the vtable pointer. Same for works references
&Struct: [ #address ]
|
+-----------+
|
v
[ Struct’s field values ]
&dyn Trait: [ #address, #vtable_ptr ]
| |
+--------------+ |
| +--+
v |
[ Struct’s field values ] |
|
+---------------+
|
v
the vtable: [ size, destructor fn-pointer, fn-pointers for methods, … ]
However, with two indirections
&Rc<Struct>: [ #address ]
|
+---+
|
v
Rc<Struct>: [ #address ]
|
|
+--+
|
v
[reference count] [ Struct’s field values ]
&Rc<dyn Trait>: [ #address ]
|
+---+
|
v
Rc<dyn Trait>: [ #address, #vtable_ptr ]
| |
| +----------------+
v |
[reference count] [ Struct’s field values ] |
|
+--------------------------------+
|
v
the vtable: [ size, destructor fn-pointer, fn-pointers for methods, … ]
you can see how turning &Rc<Struct>
into &Rc<dyn Trait>
can not work, because there’s no preexisting Rc<dyn Trait>
anywhere in memory to point to, and the existing Rc<Struct>
doesn’t have the vtable pointer in it. The &Rc<dyn Trait>
you’d like to return cannot own such that Rc<dyn Trait>
either, since references don’t have ownership.
The only things that do work for your function signature is either to return an owned rc Rc<dyn Trait>
by cloning the Rc
from the field, or a direct reference to the trait object &dyn Trait
. Which one you want depends on your use-case.