The type fn(Data: &T)
is a shorthand for a type involving a higher-ranked lifetime, namely for<'a> fn(&'a T)
. This type is not a type of the form fn(A)
for some fixed type A
, and hence it doesn’t match the Debug
implementation for single-argument function pointers in the standard library.
Unfortunately there is an infinite number of such types to consider and no generic way to create trait implementations for all of them at once, currently, so the standard library just doesn’t implement Debug
(or other traits implemented by fn
pointers like Eq
, Ord
, Hash
) for any of these higher-ranked function pointer types.
In order to implement Debug
yourself for your type (which is a good idea anyways in this case because even if derive(Debug)
would work, it would only generate an implementation impl<T> Debug for Delegate<T> where T: Debug
, whereas for debug-printing a function pointer, you don’t need any additional constraints like T: Debug
on the argument types), let me get help from my IDE (rust-analyzer) which offers an Option to generate the code that derive(Debug)
would’ve created in order for me to be able to change it:
use std::fmt;
impl<T: fmt::Debug> fmt::Debug for Delegate<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Delegate").field(&self.0).finish()
}
}
error: implementation of `Debug` is not general enough
--> src/main.rs:13:41
|
13 | f.debug_tuple("Delegate").field(&self.0).finish()
| ^^^^^^^ implementation of `Debug` is not general enough
|
= note: `Debug` would have to be implemented for the type `for<'r> fn(&'r T)`
= note: ...but `Debug` is actually implemented for the type `fn(&'0 T)`, for some specific lifetime `'0`
Now we can change it to not have a T: Debug
bound and add some conversion of fn(&T)
to fn(&'a T)
for some concrete lifetime 'a
. I cannot use 'static
here (because T
might not support &'static T
references), so let me use the lifetime of the &self
argument instead.
impl<T> fmt::Debug for Delegate<T> {
fn fmt<'a>(&'a self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Delegate").field(&self.0 as &fn(&'a T)).finish()
}
}
This compiles now
Edit: Seems like I’ve run into a compiler bug with this Debug
implementation:
https://github.com/rust-lang/rust/issues/88562