Ce face Any
Orice tip 'static (care nu conține referințe temporare) implementează automat Any. Prin &dyn Any sau Box<dyn Any> poți ține valori de tipuri diferite și le poți verifica la rulare: is::<T>() răspunde da/nu, downcast_ref::<T>() dă Option<&T>, iar Box::downcast::<T>() recuperează valoarea.
Any este o unealtă rară. În cod obișnuit, un enum cu câte o variantă pentru fiecare tip sau un trait propriu sunt mai clare și mai sigure. Any apare la pluginuri, la sisteme generice de stocare și la valorile primite din panic::catch_unwind. Pentru numele unui tip, folosit la depanare, există std::any::type_name::<T>().
Ce returnează
type_id() returnează un TypeId; downcast_ref returnează Option<&T>.
Exemple
Exemplul 1: O listă de valori de tipuri diferite
use std::any::Any;
fn descrie(v: &dyn Any) -> String {
if let Some(n) = v.downcast_ref::<i32>() {
format!("număr întreg: {n}")
} else if let Some(s) = v.downcast_ref::<String>() {
format!("text: {s:?}")
} else if let Some(s) = v.downcast_ref::<&str>() {
format!("text literal: {s:?}")
} else if v.is::<bool>() {
String::from("valoare booleană")
} else {
String::from("tip necunoscut")
}
}
fn main() {
let valori: Vec<Box<dyn Any>> = vec![
Box::new(42),
Box::new(String::from("Iași")),
Box::new("Cluj"),
Box::new(true),
Box::new(3.14),
];
for v in &valori {
println!("{}", descrie(v.as_ref()));
}
}
Rezultat
număr întreg: 42
text: "Iași"
text literal: "Cluj"
valoare booleană
tip necunoscut
Exemplul 2: Box::downcast și type_name
use std::any::{type_name, Any};
fn main() {
let cutie: Box<dyn Any> = Box::new(vec![9, 10, 8]);
match cutie.downcast::<Vec<i32>>() {
Ok(note) => println!("note: {note:?}, media: {:.2}", note.iter().sum::<i32>() as f64 / note.len() as f64),
Err(_) => println!("nu este Vec<i32>"),
}
println!("{}", type_name::<Option<String>>());
println!("{}", type_name::<f64>());
}
Rezultat
note: [9, 10, 8], media: 9.00
core::option::Option<alloc::string::String>
f64
Greșeli frecvente
- Faci
downcast_ref::<String>()pe o valoare care este de fapt&str(sau invers) și primeștiNone. Tipul trebuie să fie exact același. - Apelezi metodele pe
&Box<dyn Any>în loc de&dyn Any:Boxeste el însușiAny, deci verificarea se face pe tipul cutiei. Foloseștev.as_ref()sau&**v. - Folosești
Anyunde unenumar fi suficient și pierzi verificarea completă a cazurilor la compilare.
Comenzi înrudite
Sized: Trait marker pentru tipurile cu dimensiune cunoscută la compilare; ?Sized permite și str, [T], dyn Trait.Send și Sync: Trait-uri marker automate prin care compilatorul previne erorile de concurență: Send = poate trece în alt fir, Sync = poate fi împărțit.fmt::Debug: Trait-ul pentru afișarea de depanare cu {:?} și {:#?}; se obține aproape mereu cu #[derive(Debug)].