In the following code, I don't understand the difference between p_a_any1 (accepted) and p_a_any2 (refused by compiler).
What is the mentioned borrowing problem ?
trait A : std::any::Any {
fn f(&self) -> ();
fn as_any(&self) -> &dyn std::any::Any;
}
struct S {
}
impl A for S {
fn f(&self) {println!("I'm an A");}
fn as_any(&self) -> &dyn std::any::Any {self}
}
fn main() {
let s = S {};
let p_any:&dyn std::any::Any = &s;
if p_any.is::<S>() {
println!("I'm an S")
}
let p_a:&dyn A = &s;
let p_a_any1 = p_a.as_any();//OK
if p_a_any1.is::<S>() {
println!("I'm an S")
}
let p_a:&dyn A = &s;
let p_a_any2:&dyn std::any::Any = &p_a;//refused ???
if p_a_any2.is::<S>() {
println!("I'm an S")
}
}
In this line, you've taken a reference top_a, which is already a reference, i.e. you have created a value of type &'_ &'_ S. Then you attempt to coerce it to &'_ dyn Any, but only 'static types implement Any, so it assumes that the inner reference must be 'static, i.e. p_a_any2 is a coerced &'_ &'static S. Then you get an error because the S referred to is a local variable, which doesn't live for 'static.
If there wasn't a lifetime error (e.g. by declaring a static instance of the S type), then this code still wouldn't do what you want, because p_a_any2.is::<S>() would be false and p_a_any2.is::<&'static S>() would be true.
Your working line let p_a_any1 = p_a.as_any() is not creating any nested references; it's coercing &S to &dyn Any inside of the as_any() method, so there's always only one level of reference.
The line of code that does not use as_any() and does not produce any double-references would be:
let p_a_any2: &dyn std::any::Any = p_a;
But this does not succeed because Rust does not currently support trait upcasting — coercion from one dyn type to another dyn type. The entire point of the pattern of creating an as_any() method is to work-around this problem by introducing a manual implementation of upcasting: putting a function in the dyn A vtable that can produce the necessary dyn Any vtable.
Hopefully trait upcasting will be finished and stabilized soon, and then we won't need any more as_any() methods. But for now, they're necessary to write this kind of code.