Summary - Trait objects
- Rust course
- Advanced
- Lesson 59/81
- 5 min
Combine Box<dyn Trait> and the vtable to build a list of shapes.
Trait objects summary
A trait object is a fat pointer made of a data pointer and a vtable; it's used as &dyn T, &mut dyn T, Box<dyn T> and Rc<dyn T>. It's needed for mixed collections and runtime choices; the price is an indirect call. The trait must be dyn compatible; incompatible methods are excluded with where Self: Sized. To get back to the concrete type, std::any::Any and downcast_ref are used.
Back to the concrete type with Any
dyn Any is a special trait object that can hold any 'static type. Which type it is can be queried at runtime:
use std::any::Any;
fn tanimla(o: &dyn Any) -> String {
if let Some(n) = o.downcast_ref::<i32>() {
format!("tamsayı {n}")
} else if let Some(s) = o.downcast_ref::<&str>() {
format!("metin: {s}")
} else {
String::from("bilinmeyen")
}
}Any is a last resort in design; an enum or a trait method is usually a better solution.
Practice Type query
Write the tanimla function above. Keep 5, "metin" and 2.5 in a Vec<Box<dyn Any>>; print the result for each on its own line.
Starter code
use std::any::Any;
fn main() {
// buraya yaz
}Sample solution
use std::any::Any;
fn tanimla(o: &dyn Any) -> String {
if let Some(n) = o.downcast_ref::<i32>() {
format!("tamsayı {n}")
} else if let Some(s) = o.downcast_ref::<&str>() {
format!("metin: {s}")
} else {
String::from("bilinmeyen")
}
}
fn main() {
let ogeler: Vec<Box<dyn Any>> = vec![Box::new(5), Box::new("metin"), Box::new(2.5)];
for o in &ogeler {
println!("{}", tanimla(o.as_ref()));
}
}Expected output
tamsayı 5 metin: metin bilinmeyen
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What does <code>downcast_ref::<T>()</code> return?
- It panics
- Box<T>
- Some(&T) if the value really is T, None otherwise Correct answer
- Always T
Explanation: Any carries the type's identity (TypeId); downcast compares that identity.
2 Test the type
if let Some(n) = o.____::<i32>() {
println!("tamsayı {n}");
}
if let Some(n) = o.downcast_ref::<i32>() {
println!("tamsayı {n}");
}
Explanation: downcast_ref gives a reference if the value is of that type.
3 Group summary
| Term | Meaning |
|---|---|
vtable |
Method table |
Box<dyn T> |
Owned trait object |
where Self: Sized |
Excluded from dyn |
dyn Any |
Runtime type query |