fn process(data: Vec<dyn Sized>) {
// How do I iterate over the `data`, and determine the type of each item at runtime?
}
It's not even possible to construct a Vec
of dyn
anything, because a Vec
's elements must be equally sized (and dyn Sized
is a contradiction), but you can make a Vec<Box<dyn std::any::Any>>
. The Box
handles the variable sizes and the Any
trait allows comparing the type of the value and downcasting.
Doing this in a verbose way:
use std::any::Any;
fn process(data: Vec<Box<dyn Any>>) {
for element in data {
if element.is::<String>() {
let s: Box<String> = element.downcast::<String>().unwrap();
println!("Got String: {s}");
} else if element.is::<i32>() {
let i: Box<i32> = element.downcast::<i32>().unwrap();
println!("Got i32: {i}");
} else {
println!("Got unknown element");
}
}
}
fn main() {
let vec: Vec<Box<dyn Any>> = vec![
Box::new(true),
Box::new("Hello!".to_string()),
Box::new(17),
Box::new(18),
Box::new("&str"),
];
process(vec);
}
Output:
Got unknown element
Got String: Hello!
Got i32: 17
Got i32: 18
Got unknown element
If you want to take the values out of the Box
:
- let s: Box<String> = element.downcast::<String>().unwrap();
+ let s: String = *element.downcast::<String>().unwrap();
- let i: Box<i32> = element.downcast::<i32>().unwrap();
+ let i: i32 = *element.downcast::<i32>().unwrap();
If you keep the type annotations for s
and i
, you can also remove the turbofish after downcast
:
- let s: String = *element.downcast::<String>().unwrap();
+ let s: String = *element.downcast().unwrap();
- let i: i32 = *element.downcast::<i32>().unwrap();
+ let i: i32 = *element.downcast().unwrap();
And if you don't want to move the values but work with references:
use std::any::Any;
fn process(data: &[Box<dyn Any>]) {
for element in data {
if element.is::<String>() {
let s: &String = element.downcast_ref().unwrap();
println!("Got String: {s}");
} else if element.is::<i32>() {
let i: &i32 = element.downcast_ref().unwrap();
println!("Got i32: {i}");
} else {
println!("Got unknown element");
}
}
}
fn main() {
let vec: Vec<Box<dyn Any>> = vec![
Box::new(true),
Box::new("Hello!".to_string()),
Box::new(17),
Box::new(18),
Box::new("&str"),
];
process(&vec);
}
The last example with references can be written even nicer:
fn process(data: &[Box<dyn Any>]) {
for element in data {
if let Some(s) = element.downcast_ref::<String>() {
println!("Got String: {s}");
} else if let Some(i) = element.downcast_ref::<i32>() {
println!("Got i32: {i}");
} else {
println!("Got unknown element");
}
}
}
exactly what I want!
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.