PhantomData<T> vs PhantomData<fn() -> T> - не одно и то жеPhantomData<T> указывает на семантику владения T.PhantomData<fn() -> T> - лишь на то что где-то будет использоваться этот T.Drop-check будет считать, что
PhantomData<T> может вызывать Drop у T, а PhantomData<fn() -> T> - не будет.Еще одно важное отличие это авто-трейты.
PhantomData<T> наследует их от T, а вот PhantomData<fn() -> T> нет.Если
T будет !Send или !Sync, то в первом случае и ваш тип будет. А в случае функции - нет. Указатели на функции Send, Sync, Unpin и прочие Freeze независимо от типов аргументов и возвращаемого типа.#[derive(Default)]
struct Foo<T>(PhantomData<T>);
#[derive(Default)]
struct Bar<T>(PhantomData<fn() -> T>);
let foo: Foo<Rc<u8>> = Foo::default();
let bar: Bar<Rc<u8>> = Bar::default();
std::thread::spawn(|| { drop(foo); }); // error: `Rc<u8>` cannot be sent between threads safely
std::thread::spawn(|| { drop(bar); }); // success!
Следует учитывать, что
PhantomData<fn(T)> переворачивает ковариантность, так что его стоит использовать когда именно это и нужно.Удачной вам охоты на фантомные данные 👻