我试图用Higher-Rank Trait Bound定义一个trait Foo,在&'a Self类型IntoIterator上.换句话说,我想要求实现类型T可以通过不可变借位迭代(即,&T: IntoIterator).

我还想要一个函数bar,它接受类型为T: Foo的参数.但这给了我一个错误.

以下是MRE:(playground在夜间1.79)

trait Foo
where for<'a> &'a Self: IntoIterator
{}

fn bar<T: Foo>(_: T) {}

这就是错误:

error[E0277]: `&'a T` is not an iterator
 --> src/lib.rs:5:11
  |
5 | fn bar<T: Foo>(_: T) {}
  |           ^^^ `&'a T` is not an iterator
  |
  = help: the trait `for<'a> Iterator` is not implemented for `&'a T`, which is required by `for<'a> &'a T: IntoIterator`
  = help: the trait `Iterator` is implemented for `&mut I`
  = note: required for `&'a T` to implement `for<'a> IntoIterator`
note: required by a bound in `Foo`
 --> src/lib.rs:2:25
  |
1 | trait Foo
  |       --- required by a bound in this trait
2 | where for<'a> &'a Self: IntoIterator
  |                         ^^^^^^^^^^^^ required by this bound in `Foo`

For more information about this error, try `rustc --explain E0277`.

我不明白这个错误.为什么要用for<'a> Iterator来实现&'a TIteratortrait 似乎不是IntoIterator的超级trait .

为什么他说是"required for 100 to implement 101"?毕竟,这正是我为Foo定义的trait边界,也就是我为bar参数的类型设置的边界,不是吗?

我觉得我在这里错过了一些基本的东西,但这是一种罕见的情况,当我发现编译器的错误信息根本没有帮助时.

PS:

这句话更让人困惑:"the trait 100 is implemented for 101".I到底是什么?

推荐答案

让我们来看看一个classic 的超级trait :

trait Foo: IntoIterator {}

fn bar<T: Foo>() {}

为了编译barT必须是格式良好的(类似于"能够存在").因为T需要FooFoo需要IntoIterator,这意味着我们必须证明T: IntoIterator.

如果没有编译器的特殊支持,我们将无法证明它.bar()没有列出T: IntoIterator作为一个边界,所以我们无法证明T: IntoIterator.

但是为了让我们不必每次使用Foo时都写T: IntoIterator,编译器可以帮助我们.它elaboratesFoo: IntoIterator绑定,即使它implied.如果我们有一个T: Foo的界限,它是implies,我们也有一个T: IntoIterator的界限.现在我们可以简单地满足要求T: IntoIterator.

但事实是,编译器并不总是详细说明特征的界限.It only does so for supertraits,即形式trait Trait: Supertraittrait Trait where Self: Supertrait的边界(因为前者本质上是后者的语法糖).

你的边界不是超特征边界,因为它是在for<'a> &'a Self,而不是在Self.因此,编译器并没有详细说明它,但对格式良好的要求仍然存在—只是你必须明确地拼写出来:

fn bar<T: Foo>(_: T)
where
    for<'a> &'a T: IntoIterator,
{
}

Playground.


An aside about the error message:

编译器在这里太聪明了.它试图证明T: IntoIterator,它看到有一个毯子实施impl<I: Iterator> IntoIterator for I.所以它告诉你你错过了一个Iterator小精灵,而你真的错过了一个IntoIterator小精灵.我读到了一个修改这个的建议,但我现在找不到它.

help: the trait `Iterator` is implemented for `&mut I` 段确实令人困惑.编译器会定期列出现有的impl(因为也许你认为你应该匹配一个),我相信在这种情况下,它只列出这个是因为它认为你可能混淆了&T&mut T,也就是说,你认为&T有一个Iterator impl(这将匹配你的边界),但事实上&mut T有一个impl.现在,即使你需要&mut T,这仍然不能解决问题,因为这个impl也需要referent为Iterator,但是编译器不会分析到这个深度.

Rust相关问答推荐

将内部类型作为参数的泛型 struct 上的方法

在Rust中赋值变量有运行时开销吗?

在自身功能上实现类似移动的行为,以允许通过大小的所有者进行呼叫(&;mut;self)?

"value is never read警告似乎不正确.我应该忽略它吗?

交换引用时的生命周期

如何定义实现同名但返回类型不同的 struct 的函数

如何正确重新排列代码以绕过铁 rust 借入判断器?

是否可以在不切换到下一个位置的情况下获得迭代器值:

Rust编译器似乎被结果类型与anyhow混淆

如何实现Deref;多次;?

类型生命周期绑定的目的是什么?

为什么我必须使用 PhantomData?在这种情况下它在做什么?

提取指向特征函数的原始指针

Option<&T> 如何实现复制

如何在 Rust 中将 UTF-8 十六进制值转换为 char?

需要括号的宏调用中的不必要的括号警告 - 这是编写宏的糟糕方法吗?

`if let` 只是另一种编写其他 `if` 语句的方式吗?

在 Rust 中有条件地导入?

为什么 Rust 标准库同时为 Thing 和 &Thing 实现特征?

返回 &str 但不是 String 时,borrow 时间比预期长