Reputation: 722
I am learning Rust and don't understand why the following doesnt work. I gather we are unable to clone an Rc pointer over a trait object? How am I to pass such a reference to an function defined only by a trait, as attempted in some_function
?
use std::rc::Rc;
trait SomeTrait {}
struct SomeThing {}
impl SomeTrait for SomeThing {}
fn some_function(s: Rc<dyn SomeTrait>) {}
fn another_function(s: &Rc<dyn SomeTrait>) {}
fn main() {
let s = Rc::new(SomeThing{});
// This doesnt work
some_function(Rc::clone(&s));
// I could do this
some_function(s);
// But then I could not do this
some_function(s);
// For that matter, neither can I do this
another_function(&s);
}
Upvotes: 5
Views: 684
Reputation: 42272
If you look at the error messages of the compiler you will see this:
error[E0308]: mismatched types
|
14 | some_function(Rc::clone(&s));
| ^^ expected trait object `dyn SomeTrait`, found struct `SomeThing`
|
= note: expected reference `&Rc<dyn SomeTrait>`
found reference `&Rc<SomeThing>`
That means the compiler mis-infers the type of s
to Rc<SomeThing>
instead of the Rc<dyn SomeTrait>
you were looking for, which can be confirmed by the usual trick of providing a blatantly incorrect type to let s
:
error[E0308]: mismatched types
--> src/main.rs:11:17
|
11 | let s: () = Rc::new(SomeThing{});
| -- ^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Rc`
| |
| expected due to this
|
= note: expected unit type `()`
found struct `Rc<SomeThing>`
Since Rust wrappers are invariant, an Rc<SomeThing>
and an Rc<dyn SomeTrait>
are completely incompatible values, there is no way to just use one for the other.
The solution is to simply explicitely type s
correctly:
use std::rc::Rc;
trait SomeTrait {}
struct SomeThing {}
impl SomeTrait for SomeThing {}
fn some_function(s: Rc<dyn SomeTrait>) {}
fn another_function(s: &Rc<dyn SomeTrait>) {}
fn main() {
let s: Rc<dyn SomeTrait> = Rc::new(SomeThing{});
// This doesnt work
some_function(Rc::clone(&s));
// For that matter, neither can I do this
another_function(&s);
}
Obviously the two calls in the middle can't work, as the first one will move the local Rc
, which the second one (and the final call) still want.
Upvotes: 6