Bounds在trait的关联项中是WhereBounds的子集吗?

huangapple go评论69阅读模式
英文:

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&lt;T&gt;: Ord where T: Debug;
}

> Given a reference to the associated type like &lt;X as Example&gt;::Output&lt;Y&gt;,
> the associated type itself must be Ord, and the
> type Y must be Debug.

This variant also compiles

trait Example {
    type Output&lt;T&gt;
    where
        Self::Output&lt;T&gt;: Ord,
        T: Debug;
}

as does this(!)

trait Example {
    type Output&lt;T&gt;: Ord
    where
        Self::Output&lt;T&gt;: 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&lt;T: Ord&gt;() {}

fn foo&lt;T: Example&gt;() {
    assert_ord::&lt;T::Output&lt;i32&gt;&gt;();
}

It compiles with:

trait Example {
    type Output&lt;T&gt;: Ord;
}

But fails with:

trait Example {
    type Output&lt;T&gt;
    where
        Self::Output&lt;T&gt;: Ord;
}

With the error:

error[E0277]: the trait bound `&lt;T as Example&gt;::Output&lt;i32&gt;: Ord` is not satisfied
  --&gt; src/lib.rs:10:18
   |
10 |     assert_ord::&lt;T::Output&lt;i32&gt;&gt;();
   |                  ^^^^^^^^^^^^^^ the trait `Ord` is not implemented for `&lt;T as Example&gt;::Output&lt;i32&gt;`
   |
note: required by a bound in `assert_ord`
  --&gt; src/lib.rs:7:18
   |
7  | fn assert_ord&lt;T: Ord&gt;() {}
   |                  ^^^ required by this bound in `assert_ord`
help: consider further restricting the associated type
   |
9  | fn foo&lt;T: Example&gt;() where &lt;T as Example&gt;::Output&lt;i32&gt;: Ord {
   |                      ++++++++++++++++++++++++++++++++++++++

But there's more: just implementing the trait will fail for the second variant will fail:

trait Example {
    type Output&lt;T&gt;
    where
        Self::Output&lt;T&gt;: Ord;
}

impl Example for () {
    type Output&lt;T&gt; = String;
}
error[E0275]: overflow evaluating the requirement `&lt;() as Example&gt;::Output&lt;T&gt; == _`
 --&gt; src/lib.rs:8:5
  |
8 |     type Output&lt;T&gt; = 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
&gt; trait Foo {
&gt; type Assoc&lt;&#39;a&gt;: Trait&lt;&#39;a&gt;;
&gt; }
&gt;

>
> Is equivalent to:
>
> rust
&gt; trait Foo where for&lt;&#39;a&gt; Self::Assoc&lt;&#39;a&gt;: Trait&lt;&#39;a&gt; {
&gt; type Assoc&lt;&#39;a&gt;;
&gt; }
&gt;

>
> ### 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
&gt; trait Foo {
&gt; type Assoc where Self: Sized;
&gt; }
&gt;

>
> Each invocation of &lt;T as Foo&gt;::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.

huangapple
  • 本文由 发表于 2023年8月4日 01:52:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76830513.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定