我可以创建一个编译错误来检查一个特征是否有另一个特征作为超特征吗?

Can I create a compile error to check if a trait has another trait as a supertrait?

我正在创建一个宏来解析用户生成的特征并为其创建辅助函数。我对使用的一些参数有类型限制,所以我一直在遵循 example in the quote crate 生成一些代码,如果未实现特征,这些代码将抛出编译错误。它并不完美,但可以完成工作:

struct _AssertSync where #ty: Sync;

我还希望能够检查该特征是否具有 Hash 作为超级特征。如果我遵循相同的模式,我会得到一个错误:

struct _AssertHash where dyn #tr: Hash;

一个完整的例子:

use std::hash::Hash;

trait BadBoi {}
trait GoodBoi: Hash {}

struct _AssertHash
where
    dyn GoodBoi: Hash;
error[E0038]: the trait `GoodBoi` cannot be made into an object
   --> src/lib.rs:6:39
    |
4   | trait GoodBoi: Hash {}
    |       ------- this trait cannot be made into an object...
5   | 
6   | struct _AssertHash where dyn GoodBoi: Hash;
    |                                       ^^^^ the trait `GoodBoi` cannot be made into an object
    |
    = help: consider moving `hash` to another trait

我有什么办法可以解决这个问题吗?

您可以使用两个函数来检查超级特征关系,例如:

fn _assert_hash_supertrait<T: $tr>() {
    fn requires_hash<T: Hash>() {}
    let _ = requires_hash::<T>;
}

这仅在绑定 T: $tr 暗示 T: Hash 时编译。如果 Hash$tr 的超级特征,那么情况就是这样。另见 .

完整示例 (Playground):

trait BadBoi {}
trait GoodBoi: Hash {}

macro_rules! foo {
    ($tr:ident) => {
        fn _assert_hash_supertrait<T: $tr>() {
            fn requires_hash<T: Hash>() {}
            let _ = requires_hash::<T>;
        }
    }
}

//foo!(GoodBoi);
foo!(BadBoi);

当然在这个解决方案中,调用 foo! 两次错误,因为 assert_hash_supertrait 被定义了两次,但是解决这个问题不是这个问题的一部分。