0

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();
}

Playground.

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));
}

Playground.

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

Playground.

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?

Román Cárdenas
  • 492
  • 5
  • 15

2 Answers2

0

This other example works:

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> = Wrapper(x.0.clone()); // clone inner Rc
}

Playground.

While it is enough for me, I think that it has too much boilerplate code. Other suggestions are welcome.

Román Cárdenas
  • 492
  • 5
  • 15
0

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.

Román Cárdenas
  • 492
  • 5
  • 15
cafce25
  • 15,907
  • 4
  • 25
  • 31