Here's the scenario, let's assume we have a trait Thing and in turn a &dyn Thing, maybe even a Vec<Box<dyn Thing>>. Now we want to turn that &dyn Thing into Any, such that it can be downcast()ed into some concrete type T.

trait Thing {
    // ...
}

struct Foo;
struct Bar;

impl Thing for Foo {
    // ...
}

impl Thing for Bar {
    // ...
}

fn maybe_foo(thing: &dyn Thing) {
    if /* `thing` is `Foo` */ {
        let foo: &Foo = /* `thing` */;
    }
}

A Solution

This is where the magic of Any comes in. In other words, the "straightforward" solution, is to add an as_any() method to Thing:

use std::any::Any;

trait Thing {
    fn as_any(&self) -> &dyn Any;
}

struct Foo;
struct Bar;

impl Thing for Foo {
    fn as_any(&self) -> &dyn Any {
        self
    }
}

impl Thing for Bar {
    fn as_any(&self) -> &dyn Any {
        self
    }
}

fn maybe_foo(thing: &dyn Thing) {
    if let Some(foo) = thing.as_any().downcast_ref::<Foo>() {
        // `thing` is `Foo`
    } else {
        // `thing` is not `Foo`
    }
}

However...

There is two annoyances with the above solution:

  1. The short and simple as_any() method, needs to be copy-pasted between all types implementing Thing
  2. If Thing is already implemented for many types, then it might be less desirable, to have to manually add an as_any() method everywhere

Initial Hunch ~ Default Implementations

The initial hunch might be to add a default implementation of as_any() to Thing:

trait Thing {
    fn as_any(&self) -> &dyn Any {
        self
    }
}

Nice and easy! But wait... That doesn't seem to compile... Hmm...

error[E0277]: the size for values of type `Self` cannot be known at compilation time
 --> src/main.rs:5:9
  |
5 |         self
  |         ^^^^ doesn't have a size known at compile-time
  |
  = note: required for the cast from `&Self` to `&(dyn Any + 'static)`
help: consider borrowing the value, since `&&Self` can be coerced into `&(dyn Any + 'static)`
  |
5 |         &self
  |         +
help: consider further restricting `Self`
  |
4 |     fn as_any(&self) -> &dyn Any where Self: Sized {
  |                                  +++++++++++++++++

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

What's going on?

So, long story short. Since there are no trait bounds constraining Thing, then self could both be sized or have an unknown size (i.e. dynamically sized). This is an issue, since the default implementation needs to apply to everything implementing Thing.

Next Hunch ~ Sized

The next hunch might be to follow the suggestion from the compiler. In other words, adding a Sized (ref) constraint to Thing.

Additionally, since Any has a 'static lifetime constraint, then it needs to be added to Thing as well.

trait Thing: Sized + 'static {
    fn as_any(&self) -> &dyn Any {
        self
    }
}

Requiring both Sized and a 'static lifetime, might seem reasonable, considering we have a &dyn Thing or Vec<Box<dyn Thing>>.

However, attempting to compile, and it immediately becomes clear, why this is not the solution either:

error[E0038]: the trait `Thing` cannot be made into an object
  --> src/main.rs:24:22
   |
24 | fn maybe_foo(thing: &dyn Thing) {
   |                      ^^^^^^^^^ `Thing` cannot be made into an object
   |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
  --> src/main.rs:3:14
   |
3  | trait Thing: Sized + 'static {
   |       -----  ^^^^^ ...because it requires `Self: Sized`
   |       |
   |       this trait cannot be made into an object...
   = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Thing` for this new enum and using it instead:
             Bar
             Foo

So what's going on this time?

We want to operate on a &dyn Thing, i.e. a reference to a trait object. Trait objects are dynamically sized, in other words they could be of any size. While Sized requires a known fixed/constant size. Thereby requiring Sized makes it impossible to use the dyn Thing trait object.

So what do we do?

Actual Solution

We can resolve the issue by introducing a second trait AsAny. This is then the trait that contains the fn as_any() method (and fn as_any_mut() method). Now, instead of having to manually implement AsAny for all types, then we can automatically implement it through a blanket implementation.

To be able to still use as_any() through our &dyn Thing, then we simply need to add AsAny as a requirement to Thing.

trait Thing: AsAny {
    // ...
}

trait AsAny {
    fn as_any(&self) -> &dyn Any;
    fn as_any_mut(&mut self) -> &mut dyn Any;
}

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

    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
}

Now we get the best of both words. We have an as_any() method available, without needing to update all impl Thing for XYZ. The only change needed to trait Thing is adding the AsAny requirement.

All in all, now the following works perfectly fine:

fn maybe_foo(thing: &dyn Thing) {
    if let Some(foo) = thing.as_any().downcast_ref::<Foo>() {
        println!("Foo");
    } else {
        println!("Not Foo");
    }
}

fn main() {
    maybe_foo(&Foo);
    maybe_foo(&Bar);

    let things: Vec<Box<dyn Thing>> = vec![
        Box::new(Foo),
        Box::new(Bar),
    ];

    for thing in &things {
        maybe_foo(thing.as_ref());
    }
}

Outputting the following:

Foo
Not Foo
Foo
Not Foo