首页 > 解决方案 > 使用特征作为幻像类型

问题描述

在 Rust 中,我想使用幻像类型来正确键入一个简单的 id:

struct Id<T> {
    val: u32,
    _type: PhantomData<T>,
}

在第一个草稿版本中,我使用了具体的结构T,一切都很好。然后在使用不同数据源的更精细的版本中,这些结构变成了特征。比方说:

trait MyArticle {
    fn get_id() -> Id<MyArticle>;
}

但是使用traits作为幻像类型会带来问题:

我当前的解决方案是在空结构和特征之间复制名称类型:

struct MyArticle_ {};

trait MyArticle {
    fn get_id() -> Id<MyArticle_>;
}

这很尴尬,但我找不到更好的。

标签: rustphantom-types

解决方案


您的样本的问题在于了解特征是什么。实际上它不是类型(这就是编译器要求的原因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>>不起作用。


推荐阅读