在下面的示例代码中,trait Foo
要求关联的类型X
实现Clone
trait。
当在do_it
函数签名中使用impl Foo<X = Baz>
语法时,cargo check
不会抱怨Baz
没有实现Clone
特征。
然而,cargo check
确实在impl Foo for Bar
块中抱怨了这个问题。
我本以为impl Foo<X = Baz>
也会以同样的方式抱怨。
trait Foo {
type X: Clone;
}
struct Bar;
struct Baz;
impl Foo for Bar {
type X = Baz; // <- complains Baz does not impl Clone trait
}
fn do_it(foo: impl Foo<X = Baz>) {} // <- does not complain
如果X
是泛型参数,则情况并非如此。在这种情况下,cargo check
表示foo: impl Foo<Bar>
不满足Clone
特性界限
trait Foo<X>
where
X: Clone,
{
}
struct Bar;
struct Baz;
fn do_it(foo: impl Foo<Baz>) {} // <- complains Baz does not impl Clone trait
这是预期行为吗?如果是,为什么?
1条答案
按热度按时间p8h8hvxi1#
这在介绍关联类型的RFC中用一个简短的句子进行了描述:
关联类型上的
BOUNDS
和WHERE_CLAUSE
是trait实现者的 * 义务 *,以及trait用户的 * 假设 *:这意味着负责证明边界成立的人不是trait的用户(在你的例子中是
do_it()
),而是trait的实现者,这与trait的泛型参数相反,后者的证明义务在用户身上。当您查看时,差异应该是显而易见的:对于泛型参数,类型是外来的,在trait实现中是未知的,所以它必须假设边界漏洞。另一方面,trait的用户有具体的类型(即使它们本身是泛型的,从trait的Angular 来看,它们仍然是具体的类型),所以它应该证明边界成立。相反,对于关联类型,情况就不同了:实现者知 prop 体的类型,而用户则假设一个泛型类型(即使像你的代码一样,它把它们限制在一个特定的类型,在一般情况下,它仍然是未知的)。
请注意,在关联类型(
type Foo where Self::Foo: Clone
)上使用 where bounds,这是与泛型关联类型一起引入的(是的,我知道我链接的RFC带来了它们,但据我所知,它们没有实现,最终作为具有不同语义的GAT的一部分实现),情况再次不同于正常的关联类型边界:用户也必须证明它们(我认为两者都需要证明,但我不确定),这是因为它们被期望用于关联类型的泛型参数,因此它们类似于traits的泛型参数或其中的where子句。