英文:
are Bounds in a trait's associated item a subset of WhereBounds?
问题
关于Bounds和WhereBounds之间的区别,文档中提到如下(https://doc.rust-lang.org/reference/items/associated-items.html#relationship-between-bounds-and-wherebounds):
trait Example {
type Output<T>: Ord where T: Debug;
}
给定对关联类型的引用,如
<X as Example>::Output<Y>
,
关联类型本身必须是Ord,而
类型Y必须是Debug。
这个变体也可以编译:
trait Example {
type Output<T>
where
Self::Output<T>: Ord,
T: Debug;
}
这个也可以(!):
trait Example {
type Output<T>: Ord
where
Self::Output<T>: Ord,
T: Debug;
}
这些是否有不同的语义?Bounds
只是一种语法上的便利,用于常见情况,即将trait bounds应用于正在定义的关联类型,而WhereBounds
则更加通用严格。
英文:
The docs say this about the difference between Bounds and WhereBounds (https://doc.rust-lang.org/reference/items/associated-items.html#relationship-between-bounds-and-wherebounds)
trait Example {
type Output<T>: Ord where T: Debug;
}
> Given a reference to the associated type like <X as Example>::Output<Y>
,
> the associated type itself must be Ord, and the
> type Y must be Debug.
This variant also compiles
trait Example {
type Output<T>
where
Self::Output<T>: Ord,
T: Debug;
}
as does this(!)
trait Example {
type Output<T>: Ord
where
Self::Output<T>: Ord,
T: Debug;
}
do these have different semantics? Is Bounds
just a syntactic convenience for the common case of applying trait bounds to the associated type being defined, while WhereBounds
is strictly more general?
答案1
得分: 2
这个函数将证明它们不相等:
fn assert_ord<T: Ord>() {}
fn foo<T: Example>() {
assert_ord::<T::Output<i32>>();
}
它编译通过:
trait Example {
type Output<T>: Ord;
}
但是在以下情况下失败:
trait Example {
type Output<T>
where
Self::Output<T>: Ord;
}
并伴随以下错误:
error[E0277]: the trait bound `<T as Example>::Output<i32>: Ord` is not satisfied
--> src/lib.rs:10:18
|
10 | assert_ord::<T::Output<i32>>();
| ^^^^^^^^^^^^^^ the trait `Ord` is not implemented for `<T as Example>::Output<i32>`
|
note: required by a bound in `assert_ord`
--> src/lib.rs:7:18
|
7 | fn assert_ord<T: Ord>() {}
| ^^^ required by this bound in `assert_ord`
help: consider further restricting the associated type
|
9 | fn foo<T: Example>() where <T as Example>::Output<i32>: Ord {
| ++++++++++++++++++++++++++++++++++++++
但是还有更多:仅仅实现特质将会对第二个变种失败:
trait Example {
type Output<T>
where
Self::Output<T>: Ord;
}
impl Example for () {
type Output<T> = String;
}
error[E0275]: overflow evaluating the requirement `<()> as Example>::Output<T> == _`
-- src/lib.rs:8:5
|
8 | type Output<T> = String;
| ^^^^^^^^^^^^^^
然而,对于第一个变种,它可以编译通过。
对于非泛型关联类型,同样的行为也可以看到。
关于这个主题几乎没有什么文档,但是GAT RFC解释了这个:
评估关联类型构造的约束条件和where子句
关联类型构造的约束条件
关联类型构造的约束条件被视为对特质本身的更高秩约束。这使它们的行为与常规关联类型的约束行为一致。例如:
trait Foo { type Assoc<'a>: Trait<'a>; }
等同于:
trait Foo where for<'a> Self::Assoc<'a>: Trait<'a> { type Assoc<'a>; }
关联类型上的
where
子句相反,关联类型上的
where
子句引入了每次使用关联类型时都必须证明的约束条件。例如:trait Foo { type Assoc where Self: Sized; }
每次调用
<T as Foo>::Assoc
都需要证明T: Sized
,而不是在其他情况下需要证明该绑定。
不过,我不确定“溢出评估要求”的错误的原因是什么。
英文:
This function will prove they're not equal:
fn assert_ord<T: Ord>() {}
fn foo<T: Example>() {
assert_ord::<T::Output<i32>>();
}
It compiles with:
trait Example {
type Output<T>: Ord;
}
But fails with:
trait Example {
type Output<T>
where
Self::Output<T>: Ord;
}
With the error:
error[E0277]: the trait bound `<T as Example>::Output<i32>: Ord` is not satisfied
--> src/lib.rs:10:18
|
10 | assert_ord::<T::Output<i32>>();
| ^^^^^^^^^^^^^^ the trait `Ord` is not implemented for `<T as Example>::Output<i32>`
|
note: required by a bound in `assert_ord`
--> src/lib.rs:7:18
|
7 | fn assert_ord<T: Ord>() {}
| ^^^ required by this bound in `assert_ord`
help: consider further restricting the associated type
|
9 | fn foo<T: Example>() where <T as Example>::Output<i32>: Ord {
| ++++++++++++++++++++++++++++++++++++++
But there's more: just implementing the trait will fail for the second variant will fail:
trait Example {
type Output<T>
where
Self::Output<T>: Ord;
}
impl Example for () {
type Output<T> = String;
}
error[E0275]: overflow evaluating the requirement `<() as Example>::Output<T> == _`
--> src/lib.rs:8:5
|
8 | type Output<T> = String;
| ^^^^^^^^^^^^^^
Whereas it compiles fine for the first variant.
The same behavior can be seen with non-generic associated types.
There is very little documentation on this subject, but the GAT RFC explains this:
> ## Evaluating bounds and where clauses
>
> ### Bounds on associated type constructors
>
> Bounds on associated type constructors are treated as higher rank
> bounds on the trait itself. This makes their behavior consistent with
> the behavior of bounds on regular associated types. For example:
>
> rust
> trait Foo {
> type Assoc<'a>: Trait<'a>;
> }
>
>
> Is equivalent to:
>
> rust
> trait Foo where for<'a> Self::Assoc<'a>: Trait<'a> {
> type Assoc<'a>;
> }
>
>
> ### where
clauses on associated types
>
> In contrast, where clauses on associated types introduce constraints
> which must be proven each time the associated type is used. For
> example:
>
> rust
> trait Foo {
> type Assoc where Self: Sized;
> }
>
>
> Each invocation of <T as Foo>::Assoc
will need to prove T: Sized
,
> as opposed to the impl needing to prove the bound as in other cases.
I'm not sure what is the reason for the "overflow evaluating the requirement" error, though.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论