This is my code:
use std::rc::{Rc, Weak};
use std::cell::RefCell;
trait Trait {}
fn push<E: Trait>(e: E) {
let mut v: Vec<Rc<RefCell<Box<dyn Trait>>>> = Vec::new();
// let x = Rc::new(RefCell::new(Box::new(e)));
// v.push(x); // error
v.push(Rc::new(RefCell::new(Box::new(e)))); // works fine
}
The v.push(x) raises this error:
error[E0308]: mismatched types
--> src/main.rs:12:12
|
7 | fn push<E: Trait>(e: E) {
| - this type parameter
...
12 | v.push(x);
| ^ expected trait object `dyn Trait`, found type parameter `E`
|
= note: expected struct `std::rc::Rc<std::cell::RefCell<std::boxed::Box<dyn Trait>>>`
found struct `std::rc::Rc<std::cell::RefCell<std::boxed::Box<E>>>`
But if I push the value (constructed with the exact same value and types) directly into the vector it compiles without error.
So why doesn't the first version compile? And what should I change to make it so that I can use x before pushing it into the vector?
It's all in the type inference. When you write:
v.push(Rc::new(RefCell::new(Box::new(e))));
Rust can tell from that context that the argument to RefCell::new() must be a Box<dyn Trait>, so despite supplying a Box<E>, it coerces it to the former type. When you write this on the other hand:
let x = Rc::new(RefCell::new(Box::new(e)));
v.push(x); // compile error
Rust first infers that x of type Rc<RefCell<Box<E>>> and you can no longer push it into a vec of Rc<RefCell<Box<dyn Trait>>>. You can change this by putting an explicit type annotation in your let binding to tell Rust upfront that you really do want a Rc<RefCell<Box<dyn Trait>>>:
use std::rc::{Rc, Weak};
use std::cell::RefCell;
trait Trait {}
fn push<E: Trait>(e: E) {
let mut v: Vec<Rc<RefCell<Box<dyn Trait>>>> = Vec::new();
let x: Rc<RefCell<Box<dyn Trait>>> = Rc::new(RefCell::new(Box::new(e)));
v.push(x); // compiles
}
playground
The important thing to understand here is that E is not the same as dyn Trait. E is some known concrete implementation of Trait while dyn Trait is a trait object with its underlying concrete implementation erased.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With