Using Rc
, I can cast an Rc
of a concrete type to a trait object:
use std::rc::Rc;
trait Foo {}
impl Foo for usize {}
fn main() {
let x: Rc<usize> = Rc::new(1);
let y: Rc<dyn Foo> = x.clone();
}
If I define a wrapper for an Rc
without the Sized
bound, I can also use trait objects:
use std::rc::Rc;
trait Foo {}
#[derive(Clone)]
struct Wrapper<T: ?Sized>(Rc<T>);
impl Foo for usize {}
fn main() {
let x: Wrapper<dyn Foo> = Wrapper(Rc::new(1));
}
However, I cannot clone a wrapper of a concrete type as a trait object:
use std::rc::Rc;
trait Foo {}
#[derive(Clone)]
struct Wrapper<T: ?Sized>(Rc<T>);
impl Foo for usize {}
fn main() {
let x: Wrapper<usize> = Wrapper(Rc::new(1));
let y: Wrapper<dyn Foo> = x.clone(); // this does not compile
}
The compiler complains with the following error:
error[E0308]: mismatched types
--> src/main.rs:13:31
|
13 | let y: Wrapper<dyn Foo> = x.clone();
| ---------------- ^^^^^^^^^ expected trait object `dyn Foo`, found `usize`
| |
| expected due to this
|
= note: expected struct `Wrapper<dyn Foo>`
found struct `Wrapper<usize>`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to previous error
I'm a little bit confused, as I don't understand why the third example does not work. Can anyone help me to get the third example working? what am I missing?
You can implement your own version of coercion to an unsized type by implementing CoerceUnsized
for your Wrapper
:
#![feature(unsize, coerce_unsized)]
use std::ops::CoerceUnsized;
use std::marker::Unsize;
impl<U: ?Sized, T: Unsize<U>> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
then the syntax you used initially does compile
fn main() {
let x: Wrapper<usize> = Wrapper(Rc::new(1));
let y: Wrapper<dyn Foo> = x.clone();
}
But since you did not include that implementation the compiler doesn't know that your type can be unsized.
Note: Right now that requires the features unsize
and coerce_unsized
though so you have to compile with a nightly compiler.