In Rust, I want to use a phantom type to properly type a simple id:
struct Id<T> {
val: u32,
_type: PhantomData<T>,
}
In a first draft version, I used concrete structs as T
, all was well. Then in a more elaborate version using differents data sources, those structs became traits. Let's say:
trait MyArticle {
fn get_id() -> Id<MyArticle>;
}
But using traits as phantom types brings problems:
T: ?Sized
, as if the size of T
was potentielly needed. I could live with that, but as the purpose of PhantomData<T>
is to tell that T
won't be used, I wonder if there is some other way?#![allow(bare_trait_objects)]
, but this warning is otherwise useful and I don't want to do that. Is there a way to allow bare_trait_object
only "when used as the type parameter for Id<T>
"?My current solution is to duplicate name types between an empty struct and a trait:
struct MyArticle_ {};
trait MyArticle {
fn get_id() -> Id<MyArticle_>;
}
This is awkward but I could not find better.
The problem with your sample lies in understanding what the trait is. And in fact it is not a type (that's why compiler asks for T: ?Sized
), but a requirement for a type. Thus the solution is fairly simple: come up with a "real" type. You got it right with a struct declaration, it can be one option. But usually it's much more convenient to use associative type for that:
trait MyArticle {
type T;
fn get_id() -> Id<Self::T>
where
Self::T: MyArticle;
}
// so given impls
struct X;
impl MyArticle for X {
type T = u32;
fn get_id() -> Id<u32> {
todo!()
}
}
impl MyArticle for u32 {
type T = u32;
fn get_id() -> Id<u32> {
todo!()
}
}
So finally, you're able to call X::get_id()
, or a fully-qualified version: <X as MyArticle>::get_id()
Also, you may read there why fn get_id() -> Id<Box<dyn MyArticle>>
doesn't work.