Trait Any - How to get value?

I would like get value (object GenericVar<T>) from dyn_list .
How to do it?

use std::any::Any;
use std::any::type_name;
use core::fmt::Debug;

fn print_type_of<T: ?Sized>(_: &T) 
{
    println!("type_name: {}", std::any::type_name::<T>())
}


fn get_u16(var: &Box<GenericVar<dyn Any>>) -> Result<u16, String>
{
    let value_any = &var.value as &dyn Any;
    
    match value_any.downcast_ref::<u16>() {
        Some(v) => {
            println!("value : {}", v);
            return Ok(*v);
        }
        None => { 
            println!("ERROR");
            return Err("Cannot get u16".to_string());
        }
    }
}

/// My generic type. T : u8, u16, u32, u64, bool
#[derive(Clone, Debug)]
struct GenericVar<T: Any + 'static + ?Sized + Debug>
{
    name: String,
    value: T
}

fn main()
{
    let mut dyn_list: Vec<Box<GenericVar<dyn Any>>> = vec![];

    let var_u16 = GenericVar::<u16>{ name: "var_u16".to_string(), value: 123 };
    dyn_list.push(Box::new(var_u16));

    let element = dyn_list.get(0).unwrap();
    println!("GenericVar element0: {:?}", element);
    
    let value = get_u16(element);
    println!("GenericVar value: {:?}", value);
}

Playground

Here's your answer: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast

You're going to want to downcast from a Box<dyn T> to a Box<T>, but keep in mind that it may not work because the memory size and alignment need to be correct. Hence, the use of downcast returns a Result.

Then, to go from Box<T> to T, just dereference the Box via *

let k: Box<i32> = Box::new(10 as i32)
let m: i32 = *k; 

You can use downcast_ref in this case. Note that you need to use the generic argument corresponding to the actual type of the contained object:

    let element = dyn_list
        .get(0)
        .unwrap()
        .downcast_ref::<GenericVar<u8>>()
        .unwrap();
1 Like
error[E0599]: no method named `downcast_ref` found for reference `&std::boxed::Box<GenericVar<dyn std::any::Any>>` in the current scope
  --> src/main.rs:51:10
   |
51 |         .downcast_ref::<GenericVar<u8>>()
   |          ^^^^^^^^^^^^ method not found in `&std::boxed::Box<GenericVar<dyn std::any::Any>>`

You posted the answer yourself.

Or, in an inlined fashion:

if let Some(u16_element) =
    dyn_list[0]
        .value
        .downcast_ref::<u16>()
{
    // ...
} else {
    // ...
}

I have a problem:

error[E0277]: the size for values of type `(dyn std::any::Any + 'static)` cannot be known at compilation time
  --> src/main.rs:11:17
   |
11 | fn get_u16(var: &Box<GenericVar<dyn Any>>) -> Result<u16, String>
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
...
39 | struct GenericVar<T: Any + 'static + Sized + Debug>
   |                   - required by this bound in `GenericVar`
   |
   = help: the trait `std::marker::Sized` is not implemented for `(dyn std::any::Any + 'static)`

How to fix?

Code: Playground

GenericVar is explicitly requiring its parameter to be Sized, so it can't be dyn Any. Maybe you want to change the bound in GenericVar from Sized (which is the default anyway) to ?Sized, which means "not only Sized".

1 Like

You probably want to have Box<dyn Any> instead of Box<GenericVar<dyn Any>>. Box<GenericVar<dyn Any>> is not a useful type, as it won't have downcast methods and it will be difficult to initialize an unsized struct GenericVar<dyn Any>. I'm not sure where this type is coming from. If you use my previous suggestion in your playground, it works.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.