Rust: How to Match against Any

1k views Asked by At

I would like to store any type in a Vec, and match against the actual type that is stored in the Vec.

Here is my attempt:

use std::any::Any;

fn main() {
    let mut a = Vec::<Box<dyn Any>>::new();
    a.push(Box::new(42));
    a.push(Box::new("hello"));
    a.push(Box::new(99));
    for n in a {
        let type_id = (&*n).type_id();
        println!("{type_id:?}");
        match n {
            i32 => println!("i32"),
            str => println!("str"),
            _ => println!("unhandled type")
        }
    }
}

However this always prints "i32", and I get an unreachable pattern warning.

How do I match against Any?

2

There are 2 answers

0
Netwave On

You cannot match the type per se, but you can ask if it is of any specific type with Any::is:

use std::any::Any;

fn main() {
    let mut a = Vec::<Box<dyn Any>>::new();
    a.push(Box::new(42));
    a.push(Box::new("hello"));
    a.push(Box::new(99));
    for n in a {
        let type_id = (&*n).type_id();
        println!("{type_id:?}");
        if n.is::<i32>() {
            println!("i32")
        } else if n.is::<&str>(){
            println!("str")
        } else {
            println!("unhandled type")
        }
    }
}

Playground

0
cameron1024 On

In your example, i32 and str are acting as "identifiers" (i.e. variable names), rather than types.

To work with Any, you generally use downcast_*. For example:

fn handle(any: Box<dyn Any>) {
  if let Some(s) = any.downcast_ref::<String>() {
    println!("found a string: {}", s);
  }

  if let Some(i) = any.downcast_ref::<i32>() {
    println!("found an int: {}", i);
  }
}

If you don't care about the contained value, you can also use any.is::<T>()