简体   繁体   中英

Newtype pattern of the combinations of Rc, RefCell and Box

Because I don't want to type the code like Rc::new(RefCell::new(Box::new(MyType::new(args...)))) again and again, I decided to create the newtype RcRefBox like below:

use std::rc::Rc;
use std::cell::RefCell;

struct RcRefBox<T>(Rc<RefCell<Box<T>>>);

impl<T> RcRefBox<T> {
    fn new(value: Box<T>) -> RcRefBox<T> {
        RcRefBox(Rc::new(RefCell::new(value)))
    }
}

trait Interface {}

struct A;
impl Interface for A {}

fn main() {
    let iface: RcRefBox<Interface> = RcRefBox::new(Box::new(A));
}

The code doesn't compile with the errors below: (Playpen: http://is.gd/ITiR8Q )

<anon>:19:16: 19:35 error: the trait `core::marker::Sized` is not implemented for the type `Interface` [E0277]
<anon>:19     let iface: RcRefBox<Interface> = RcRefBox::new(Box::new(A));
                         ^~~~~~~~~~~~~~~~~~~
<anon>:19:16: 19:35 note: `Interface` does not have a constant size known at compile-time
<anon>:19     let iface: RcRefBox<Interface> = RcRefBox::new(Box::new(A));
                     ^~~~~~~~~~~~~~~~~~~
<anon>:19:38: 19:51 error: the trait `core::marker::Sized` is not implemented for the type `Interface` [E0277]
<anon>:19     let iface: RcRefBox<Interface> = RcRefBox::new(Box::new(A));
                                               ^~~~~~~~~~~~~
<anon>:19:38: 19:51 note: `Interface` does not have a constant size known at compile-time
<anon>:19     let iface: RcRefBox<Interface> = RcRefBox::new(Box::new(A));
                                               ^~~~~~~~~~~~~
error: aborting due to 2 previous errors

How can I fix those errors?

The problem is not so much with your struct itself, but with the trait you pass.

Trait objects are dynamically sized objects (do not implement Sized ).

Normally, when you specify the bounds on a generic type ( T here), you constrain it, however when Sized was introduced it was decided that it would be applied as a default bound because most generic code deals with Sized types and a result T alone means T: Sized .

There is a special "widening" bound to say " T may not be Sized ": ?Sized , which you have to apply if you wish to be able to take trait objects. Adding it to your code:

use std::rc::Rc;
use std::cell::RefCell;

struct RcRefBox<T: ?Sized>(Rc<RefCell<Box<T>>>);  // ?Sized

impl<T: ?Sized> RcRefBox<T> {                     // ?Sized
    fn new(value: Box<T>) -> RcRefBox<T> {
        RcRefBox(Rc::new(RefCell::new(value)))
    }
}

trait Interface {}

struct A;
impl Interface for A {}

fn main() {
    let iface: RcRefBox<Interface> = RcRefBox::new(Box::new(A));
}

makes it work ( http://is.gd/pSZKK2 ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM