mdsimmo
mdsimmo

Reputation: 619

How to get reference to struct from boxed trait object?

I want to insert a value of type Box<T> into a Vec<Box<Trait>> and then get a reference to that value back. (T is a generic type that implements Trait). The returned value should be of type &T

The implementation below almost works, except there is no way to convert Box<Trait> to Box<Any>.

HashSet has the (experimental) get_or_insert(), which is perfect for this, but there seems to be no version for Vec?

use std::any::Any;

trait A {}
struct B;
impl A for B {}

// How to write this function?
pub fn insert<'a, T>(vector: &mut Vec<Box<dyn A>>, value: T) -> &'a T where T: A {
    // move the value into the vector
    vector.push(Box::new(value));

    // get the reference to the inserted value back
    let it: &Box<dyn Any> = vector.last().unwrap(); // compile error
    match it.downcast_ref::<T>() {
        Some(i) => i,
        None => panic!(),
    }
}

fn main() {
    let mut vec: Vec<Box<dyn A>> = Vec::new();
    let b = B;
    let b_ref = insert(&mut vec, b);
    // can't use b here since moved, so need b_ref
}

Upvotes: 2

Views: 5006

Answers (1)

Alice Ryhl
Alice Ryhl

Reputation: 4219

You can define a helper trait that is implemented for all types like this:

pub trait AToAny: 'static {
    fn as_any(&self) -> &dyn Any;
}

impl<T: 'static> AToAny for T {
    fn as_any(&self) -> &dyn Any {
        self
    }
}

Then require it to be implemented for subtypes of A.

pub trait A: AToAny {
}

You can now call .as_any() on the &dyn A you get from the vector.

pub fn insert<'a, T: A>(vector: &'a mut Vec<Box<dyn A>>, value: T) -> &'a T {
    vector.push(Box::new(value));

    let it: &dyn Any = vector.last().unwrap().as_any();
    match it.downcast_ref::<T>() {
        Some(i) => i,
        None => panic!(),
    }
}

Upvotes: 10

Related Questions