I'm trying to write a small framework and need a Box I can downcast for a cache. I ran into this problem and frewsxcv helped me with a small piece of code we both expected to work but it doesn't:
use std::any::Any;
use std::fmt::Display;
fn main() {
log(Box::new("hi"))
}
fn log<T: Any + 'static>(value: Box<T>) {
let x = value.downcast();
}
That's because downcast is implemented on Box<Any + 'static>, not Box<T> where T: Any + 'static. The first is a boxed trait object (a concrete type), the second is actually a class of types (all Box<T> where T has a 'static lifetime and implements Any). At compile time, log will be monomorphized and the type of value will be Box<&str>.
You can fix this by casting the Box<&str> to a Box<Any> (unsizing &str to Any):
use std::any::Any;
use std::fmt::Display;
fn main() {
log(Box::new("hi"))
}
fn log<T: Any + 'static>(value: Box<T>) {
let x: Result<Box<&str>, _> = (value as Box<Any + 'static>).downcast();
}
However, I doubt this is what you want to do. There's no reason to downcast in this case because you already know the type (it's T).
You probably intended to write:
use std::any::Any;
use std::fmt::Display;
fn main() {
log(Box::new("hi"))
}
fn log(value: Box<Any + 'static>) {
let x: Result<Box<&str>, _> = value.downcast();
}
If you find my explanation a bit dense/opaque, please say so. There's a lot of jargon here.
Ah thanks a lot! That makes total sense. Please allow me a follow up question, which is closer to my actual use case which also raises the no method downcast error:
use std::any::Any;
use std::fmt::Display;
fn main() {
log(Box::new("hi"))
}
fn log(value: Box<Any + Sync + 'static>) {
let x: Result<Box<&str>, _> = value.downcast();
println!{"{}", *x.unwrap()};
}
When I add the Sync trait it doesn't work anymore. I'm a bit confused by that, the adding of traits shouldn't matter for this case should it?