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:
- The compiler makes me declare
T: ?Sized
, as if the size ofT
was potentielly needed. I could live with that, but as the purpose ofPhantomData<T>
is to tell thatT
won't be used, I wonder if there is some other way? - I get the warning: "trait objects without an explicit 'dyn' are deprecated". I can get rid of it with global
#![allow(bare_trait_objects)]
, but this warning is otherwise useful and I don't want to do that. Is there a way to allowbare_trait_object
only "when used as the type parameter forId<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: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.