我有一个特点和简单的 struct :

use std::path::{Path, PathBuf};

trait Foo {
    type Item: AsRef<Path>;
    type Iter: Iterator<Item = Self::Item>;

    fn get(&self) -> Self::Iter;
}

struct Bar {
    v: Vec<PathBuf>,
}

我想实现BarFootrait :

impl Foo for Bar {
    type Item = PathBuf;
    type Iter = std::slice::Iter<PathBuf>;

    fn get(&self) -> Self::Iter {
        self.v.iter()
    }
}

然而,我得到了这个错误:

error[E0106]: missing lifetime specifier
  --> src/main.rs:16:17
   |
16 |     type Iter = std::slice::Iter<PathBuf>;
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ expected lifetime parameter

我找不到方法来指定关联类型中的生存时间.我特别想表达的是,迭代器不能超过self个生命周期.

我必须如何修改Foo-trait或Bar-trait实现才能使其工作?

Rust playground

推荐答案

你的问题有两种解决方案.让我们从最简单的一个开始:

Add a lifetime to your trait

trait Foo<'a> {
    type Item: AsRef<Path>;
    type Iter: Iterator<Item = Self::Item>;
    
    fn get(&'a self) -> Self::Iter;
}

这就要求你在使用该特征的任何地方都要标注生命周期.当你实现trait时,你需要做一个通用的实现:

impl<'a> Foo<'a> for Bar {
    type Item = &'a PathBuf;
    type Iter = std::slice::Iter<'a, PathBuf>;
    
    fn get(&'a self) -> Self::Iter {
        self.v.iter()
    }
}

当泛型参数需要trait时,还需要确保对trait对象的任何引用都具有相同的生存期:

fn fooget<'a, T: Foo<'a>>(foo: &'a T) {}

Implement the trait for a reference to your type

与其为你的类型实现trait,不如为你的类型实现trait.这种trait 永远不需要通过这种方式了解任何关于生命的信息.

然后,trait函数必须按值获取其参数.在您的情况下,您将实施以下特征作为参考:

trait Foo {
    type Item: AsRef<Path>;
    type Iter: Iterator<Item = Self::Item>;
    
    fn get(self) -> Self::Iter;
}

impl<'a> Foo for &'a Bar {
    type Item = &'a PathBuf;
    type Iter = std::slice::Iter<'a, PathBuf>;
    
    fn get(self) -> Self::Iter {
        self.v.iter()
    }
}

你的fooget函数现在变得简单了

fn fooget<T: Foo>(foo: T) {}

问题是fooget函数不知道T实际上是&Bar.当您调用get函数时,实际上是从foo变量中移出.你没有移出对象,你只是移动了引用.如果fooget函数try 调用get两次,该函数将无法编译.

如果希望fooget函数只接受Foo trait用于引用的参数,则需要显式声明以下界限:

fn fooget_twice<'a, T>(foo: &'a T)
where
    &'a T: Foo,
{}

where子句确保只为引用调用此函数,其中Foo是为引用而不是类型实现的.这两种方法也可以同时实施.

从技术上讲,编译器可以自动推断fooget_twice年内的生存期,因此您可以将其编写为

fn fooget_twice<T>(foo: &T)
where
    &T: Foo,
{}

但这还不够聪明.


对于更复杂的情况,可以使用尚未实现的Rust 功能:Generic Associated Types(GATs).issue 44265年正在追踪这方面的工作.

Rust相关问答推荐

是否有一种可靠的方法可以将Arc弦乐转换/转换为Arc Vec u8>>

使用InlineTables序列化toml ArrayOfTables

Rust,polars CSV:有没有一种方法可以从impll BufRead(或任何字节迭代器)中读取CSV?

阻止websocket中断的中断中断的终端(操作系统错误4)

展开枚举变量并返回所属值或引用

将大小为零的类型实例存储到空指针中

关于如何初始化弱 struct 字段的语法问题

在析构赋值中使用一些现有绑定

什么时候使用FuturesOrdered?

Rust移动/复制涉及实际复制时进行检测

Rust wasm 中的 Closure::new 和 Closure::wrap 有什么区别

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

如何返回 struct 体中向量的切片

如何使用tracing-subscriberRust crate 构建多编写者、全局过滤订阅者

没有明确地说return会产生错误:match arms have incompatible types

如果不满足条件,如何在 Rust 中引发错误

如何在 C++ 和 Rust 之间共享 pthread 同步原语?

在使用大型表达式时(8k 行需要一小时编译),是否可以避免 Rust 中的二次编译时间?

如何在没有 `make_contiguous()` 的情况下对 VecDeque 进行排序或反转?

如何重写这个通用参数?