Casting between Any and function or struct's method returns None

Hello, simple code blow:

    struct FF;
    impl FF {
        fn ff() {}
    }

    fn ff() {}

    let c = &ff as &dyn Any;
    let c = c.downcast_ref::<fn()>().unwrap();
    /// why does downcat() return None ?

    let c = &FF::ff as &dyn Any;
    let c = c.downcast_ref::<fn()>().unwrap();
    /// return None too


    debug_assert!(*c==FF::ff); // compiles Ok
    debug_assert!(c==FF::ff); // compiles Error, why ?

So what is correct usage for the above issues?

1 Like

&ff is a reference to function item type, which is probably not what you intended. in rust, function pointers and function items are distinct types, but the latter can cocerce to the former. try this instead:

let c = &(ff as fn()) as &dyn Any;
let c = c.downcast_ref::<fn()>().unwrap();

as the compiler suggested, it's a type error.

again, you are probably confused about rust function pointer types and C function pointers. see:

https://doc.rust-lang.org/stable/reference/types/function-pointer.html#function-pointer-types

5 Likes

Thanks, you give the right answer. It works. Yes, I am really confused about function usage between rust and C. And I have carefully read the help doc about function item and function pointer.

The important thing to notice is that all function items have distinct types, which are not function pointers (they are ZSTs actually). The reason for this is to allow the compiler to inline functions/use a different calling convention on them, even if they are passed as arguments or something.

But, if you need to, you can cast any of these types to the corresponding function pointer type, which uses a uniform calling convention. In a way, that is already a kind of type erasure.

You can see this here:

The function item types are unnameable, but using some generics, it is possible to refer to them.

So here we can see that it is actually possible to downcast them if you know the original function item type (but at that point it really doesn't make sense to do so):

I'll just add a minor point: Instead of using as to cast a function item type to a fn pointer, simple coercion also works.

    fn f1() {
    }

    let f_ptr: fn() = f1;

https://doc.rust-lang.org/1.82.0/reference/type-coercions.html#coercion-types

  • Function item types to fn pointers
1 Like