Downcasting Box<dyn Any> to arbitrary types

I tried with such error as result:

error[E0597]: pet does not live long enough
--> src/main.rs:81:34
|
80 | fn eat_any(pet: &mut dyn AsAny) {
| --- binding pet declared here
81 | let pet: &mut dyn Any = &mut pet.as_any();
| -----^^^---------
| | |
| | borrowed value does not live long enough
| cast requires that pet is borrowed for 'static
...
91 | }
| - pet dropped here while still borrowed

You can't obtain a mutable reference from an immutable reference, and you can't use a non-&'static reference with Any (because Any can't distinguish between lifetimes at runtime).

You'll need to add an as_any_mut method to the AsAny trait outlined above.

1 Like

Yeah, you need to ensure things are mutable and there are mutable references to them. Also there is the need for a 'static. I managed to get it working like so:

// Experiments in using downcasting Any into concrete type.
//
use std::any::Any;

// The indirection through `as_any_mut` is because using `downcast_ref`
// on `Box<A>` *directly* only lets us downcast back to `&A` again.
// The method ensures we get an `Any` vtable that lets us downcast
// back to the original, concrete type.
trait AsAny {
    fn as_any_mut(&mut self) -> &mut dyn Any;
}

#[derive(Debug)]
struct Cat {}

#[derive(Debug)]
struct Dog {
    name: String,
}

impl<T: 'static> AsAny for T {
    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
}
fn set_name(pet: &mut dyn AsAny, name: &str) {
    let pet: &mut dyn Any = pet.as_any_mut();

    if let Some(cat) = pet.downcast_mut::<Cat>() {
        println!("Cannot set name of Cat: {:?}", cat);
    } else if let Some(dog) = pet.downcast_mut::<Dog>() {
        dog.name = name.to_string();
        println!("Set name of Dog to: {:?}", dog.name);
    } else {
        println!("Cannot set name of {:?}.", pet);
    }
}

fn main() {
    let mut dog = Dog {
        name: "Fido".to_string(),
    };
    set_name(&mut dog, "Bonzo");

    let mut cat = Cat {};
    set_name(&mut cat, "Tiddles");
}
1 Like

Eating cat.8
Eating dog.

I tried to create vector of any :

#[derive(Debug)]
struct AllPets {
pets: Vec
}

error[E0277]: the size for values of type `(dyn AsAny + 'static)` cannot be known at compilation time
   --> src/main.rs:167:11
    |
167 |     pets: Vec<AsAny>
    |           ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `(dyn AsAny + 'static)`
note: required by an implicit `Sized` bound in `Vec`

Any idea?

AsAny is not a type, it's a trait. Only dyn AsAny is a type, but it's dynamically-sized, so you can't manipulate it by-value. dyn Trait must always be behind some sort of indirection. If you want an owned dyn Trait, you'll have to put it in an owning smart pointer such as Box or Rc.


But please consult an introductory Rust guide. This is very basic stuff and unrelated to your original question. You could have found the answer to your last 2 or 3 questions by reading the Book.

Try something like:

struct AllPets {
    pets: Vec<Box<dyn AsAny>>,
}

And create one like:

    let mut cat = Box::new(Cat { lives: 1 });
    let mut dog = Box::new(Dog {
        name: "Elvis".to_string(),
    });
    let pets = AllPets {
        pets: vec![cat, dog],
    };
1 Like

That is no doubt true, it's all in the book. However after having read the book and been using Rust for four years I have been struggling to get this working as I follow this thread. It's not all as "obvious" as you think. Not to me anyway. It's been good to have this chat here.

Thanks.

2 Likes