std::any::Any trait object downcast

I'm trying to call Any::downcast() on a trait object A that has Any as its supertrait. But it does not compile.

The code is at: (playground)

use std::any::Any;

trait Shape: Any {
    fn area(&self) -> f64;
}

struct Circle {
    radius: f64,
}

impl Shape for Circle {
    fn area(&self) -> f64 {
        std::f64::consts::PI * self.radius * self.radius
    }
}

type ShapeBox = Box<dyn Shape + Send + 'static>;

fn main() {
    let shapes: Vec<ShapeBox> = vec![
        Box::new(Circle { radius: 2.0 }),
        Box::new(Circle { radius: 3.0 }),
        Box::new(Circle { radius: 4.0 }),
    ];

    for shape in shapes {
        if let Ok(circle) = shape.downcast::<Circle>() {
            println!("Circle with radius {} has area {}", circle.radius, shape.area());
        } else {
            println!("Unknown shape");
        }
    }
}

The error is :

error[E0599]: no method named `downcast` found for struct `Box<dyn Shape + Send>` in the current scope
  --> src/main.rs:27:35
   |
27 |         if let Ok(circle) = shape.downcast::<Circle>() {
   |                                   ^^^^^^^^ method not found in `Box<dyn Shape + Send>`
   |
   = note: the method was found for
           - `Box<(dyn Any + 'static), A>`
           - `Box<(dyn Any + Send + 'static), A>`
           - `Box<(dyn Any + Send + Sync + 'static), A>`

For more information about this error, try `rustc --explain E0599`.

I don't understand why downcast was not found for the trait object. Shouldn't the supertrait Any help?

Btw, if I changed to use downcast_ref instead, I can make things work. But I wanted to downcast into an owned object.

You don't have a Box<dyn Any>, you have a Box<dyn OtherTrait>. Downcasting is only defined on Box<dyn Any> itself. You can't currently convert a subtrait to its supertrait, but it may eventually work one day.

6 Likes
// on stable Rust
trait Shape: Any {
    ...
    fn as_any(&self) -> &(dyn Any + 'static);
}

// on nightly Rust
#![feature(trait_upcasting)]
let any_shape: &DynAny = &*shape;

i.e. Rust Playground or Rust Playground

1 Like

Thanks. However, as_any() returns a reference to the object, not an owned object. (I did the same thing after I realized that it's basically not possible to get owned object. ).

Also, with a reference, we would call downcast_ref, not downcast.

That's due to the ownership in your code, i.e. downcast consumes the ownership but you use shape again, which is irrelevant to the casting. The Boxing casting works too:

// stable
trait Shape: Any {
    ...
    fn to_any(self: Box<Self>) -> Box<DynAny>;
}

// nightly
let any_shape: Box<DynAny> = shape;

Rust Playground or Rust Playground

1 Like

Got it, thank you!

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.