涉及关联类型的不满足特征界限

Unsatisfied trait bound involving associated type

密码

pub trait Q<S> {
    fn f();
}

pub trait A {
    type I;
    type F: Q<Self::I>;
}

// this works (1)
//
// pub struct S<T>
// where
//     T: A
// {                 

// unsatisfied trait bound (2)
pub struct S<T>                                  
where
    T: A<I = bool>,
{

    t: T,
}

编译失败:

error[E0277]: the trait bound `<T as A>::F: Q<bool>` is not satisfied
  --> src/main.rs:18:1
   |
18 | / pub struct S<T>                                  
19 | | where
20 | |     T: A<I = bool>,
21 | | {
22 | |     t: T,
23 | | }
   | |_^ the trait `Q<bool>` is not implemented for `<T as A>::F`
   |
   = help: consider adding a `where <T as A>::F: Q<bool>` bound
   = note: required by `A`

有趣的是,如果您使用注释掉的行 (1) 而不是 (2),它会起作用。如果将关联类型 I 转换为通用类型(写入 trait A<I>A<bool>),它也有效。

impl<T> S<T>
    where T: A
{
    fn g() {
        T::F::f()
    }
}

第 (1) 行或通用类型 I 成功,因此在这些情况下确实假定 T::F : Q<bool>

为什么在第 (1) 行或泛型类型中自动假定特征绑定,但在第 (2) 行中却没有?

我们可以在每次使用T: A<I=bool>时不附加where T::F: Q<bool>的情况下修复上面的代码吗?

从 Rust 1.18 开始,编译器要求您编写这些边界以使类型格式良好。基本上,为了使绑定 T: A<I = bool> 成立,要求绑定 T::F: Q<bool> 也成立。例如,如果某些类型试图像这样实现 A

struct Y;
struct Z;

impl A for Y {
    type I = bool;
    type F = Z; // Z does not implement Q<bool>
}

那么 Y 就不是合式的,因为绑定的 T::F: Q<bool> 不成立(事实上,编译器在 impl 上给出了一个错误)。但令人沮丧的是,目前,只要出现绑定 T: A<I = bool>,就必须明确给出绑定 T::F: Q<bool>。在某种程度上,它让编译器放心,嘿,T::I = bool 也有!

Why is the trait bound automatically assumed with line (1) or generic types, but not with line (2)?

对于第 (1) 行,边界将是 T::F: Q<T::I>,这 恰好是 A 的要求(用 T 代替Self)。事实上,我们也可以像这样等价地写出边界:

pub trait A
where
    Self::F: Q<Self::I>,
{
    type I;
    type F;
}

对于第 (2) 行,绑定 T::F: Q<bool> 可能看起来只是将 T::I 替换为 bool 的问题,但这种差异对编译器很重要; T::I 是关联类型,而 bool 是具体类型。


Rust 开发人员正在考虑改进编译器,以便 having the compiler infer those bounds 不必在整个地方重复这样的边界。