我正在try 实现类型的特征,以便可以将对该类型的引用转换为具有Item个实现特定特征的迭代器

具体而言,请考虑以下代码:

struct Arena;

pub trait Scan {
    fn scan(&self, arena: &mut Arena);
}

impl<'a, 'b, Iterable, Item> Scan for Iterable
where
    &'b Iterable: IntoIterator<Item = Item>,
    Item: Scan + 'a,
{
    fn scan(&self, arena: &mut Arena) {
        for item in (&self).into_iter() {
            item.scan(arena);
        }
    }
}

(这是playground 上的See个例子)

编译器抱怨道,在Item下划线:

the type parameter `Item` is not constrained by the impl trait, self type, or predicates
unconstrained type parameter

我现在真的不明白我在错误的方向上走到哪里:对我来说,看起来泛型实现是否受到低于where的条件的很大限制.我如何向编译器解释这个 idea ?

推荐答案

当您编写泛型特征实现(如

impl<'a, 'b, Iterable, Item> Scan for Iterable

要求所有泛型类型都出现在实现特征的类型的定义中.在你的情况下,Iterable在那里,而Item不在那里.

但你并不真的需要Item个才能成为通用的.我认为您添加它只是为了给它写一个约束.理想情况下,您希望编写如下内容:

impl<'a, 'b, Iterable> Scan for Iterable
where
    &'b Iterable: IntoIterator<Item : Scan + 'a>,

不幸的是,这仍然是一个不稳定的功能associated_type_bounds.

但幸运的是,您不需要与之绑定的关联类型.您可以改为这样写:

impl<'a, 'b, Iterable> Scan for Iterable
where
    &'b Iterable: IntoIterator,
    <&'b Iterable as IntoIterator>::Item : Scan + 'a,

现在约束起作用了,但是生命周期失败了!

error[E0309]: the parameter type `Iterable` may not live long enough
  --> src/lib.rs:27:19
   |
27 |     &'b Iterable: IntoIterator,
   |                   ^^^^^^^^^^^^ ...so that the reference type `&'b Iterable` does not outlive the data it points at
   |
help: consider adding an explicit lifetime bound...
   |
23 | impl<'a, 'b, Iterable: 'b> Scan for Iterable
   |                      ++++

如果你按照编译器的建议go 做,加上Iterable: 'b和...现在,如果函数本身的实现失败:

error: lifetime may not live long enough
  --> src/lib.rs:31:21
   |
23 | impl<'a, 'b, Iterable> Scan for Iterable
   |          -- lifetime `'b` defined here
...
29 |     fn scan(&self, arena: &mut Arena)
   |             - let's call the lifetime of this reference `'1`
30 |     {
31 |         for item in (&self).into_iter() {
   |                     ^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'b`

这实际上是意料之中的,因为匿名生存期&self'b无关,并且您不能更改这一点,因为您不能向函数特征的实现添加约束.

解决这个问题的一个显而易见的解决方案(如果没有任何其他代码,它可能不适合您)是实现&'b Iterable的特征.这样一来,&self实际上是&&'b Iterable,所有的东西都可以放在一起.此外,Iterable: 'b现在是隐含的,不再需要:

impl<'a, 'b, Iterable> Scan for &'b Iterable
where
    &'b Iterable: IntoIterator,
    <&'b Iterable as IntoIterator>::Item : Scan + 'a,
{
    fn scan(&self, arena: &mut Arena)
    {
        for item in self.into_iter() {
            item.scan(arena);
        }
    }
}

顺便说一句,我认为'a岁的生命周期 基本上是没用的.

Rust相关问答推荐

什么样的 struct 可以避免使用RefCell?

是否可以为`T:Copy`执行`T. clone`的测试

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

在Rust中显式装箱受生存期限制的转换闭包

支持TLS的模拟HTTP服务器

如何正确地将App handler传递给Tauri中的其他模块?

取得本地对象字段的所有权

作为1字节位掩码的布尔值 struct

程序在频道RX上挂起

为什么 Rust 创建的 f32 小于 f32::MIN_POSITIVE?

UnsafeCell:它如何通知 rustc Select 退出基于别名的优化?

为什么这个闭包没有实现Fn?

为什么Rust编译器会忽略模板参数应具有静态生命周期?

Rust 程序中的内存泄漏

为什么 Rust 的临时值有时有参考性有时没有?

Rust:`sort_by` 多个条件,冗长的模式匹配

了解 Rust 闭包:为什么它们持续持有可变引用?

如何连接 Rust 中的相邻切片

&str 的编译时拆分是否可能?

在传输不可复制的值时实现就地枚举修改