在Rust中,我想使用幻影类型来正确地键入一个简单的id:
struct Id<T> {
val: u32,
_type: PhantomData<T>,
}
在第一个草案版本中,我使用了具体的结构作为T
,一切都很好。然后,在使用不同数据源的更精细版本中,这些结构变成了特征。比方说:
trait MyArticle {
fn get_id() -> Id<MyArticle>;
}
但使用特征作为幻影类型会带来问题:
- 编译器让我声明
T: ?Sized
,就好像可能需要T
的大小一样。我可以接受,但由于PhantomData<T>
的目的是告诉T
不会被使用,我想知道是否有其他方法 - 我得到警告:;不赞成使用没有显式"dyn"的trait对象;。我可以用全局
#![allow(bare_trait_objects)]
来消除它,但这个警告在其他方面很有用,我不想这么做。是否有一种方法允许CCD_ 7仅";当用作CCD_ 8">
我目前的解决方案是在空结构和特征之间重复名称类型:
struct MyArticle_ {};
trait MyArticle {
fn get_id() -> Id<MyArticle_>;
}
这很尴尬,但我找不到更好的了。
样本的问题在于理解特征是什么。事实上,它不是类型(这就是编译器要求T: ?Sized
的原因(,而是对类型的要求。因此,解决方案相当简单:;真实的";类型你用结构声明做对了,它可以是一个选项。但通常使用关联类型更方便:
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!()
}
}
最后,您可以调用X::get_id()
,或者完全限定的版本:<X as MyArticle>::get_id()
此外,你可能会在那里读到为什么fn get_id() -> Id<Box<dyn MyArticle>>
不起作用。
这里的问题是特征本身不是类型,尽管dyn Trait
是。因此,当您编写Id<MyArticle>
时,它实际上意味着Id<dyn MyArticle>
(因此发出警告(,如果MyArticle
不是对象安全的,它就不会编译。
在这种特殊情况下,您可以使MyArticle
对象安全:
use std::marker::PhantomData;
struct Id<T: ?Sized> {
val: u32,
_type: PhantomData<T>,
}
trait MyArticle {
fn get_id() -> Id<dyn MyArticle> where Self: Sized;
}
如果你不能或不想让trait对象安全,那么我认为你的空结构解决方案是可行的。请注意,如果您只需要一个空的结构,您可以使用只写struct MyArticle_;
。