问题描述
我具有这种特征和简单的结构:
I have this trait and simple structure:
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>,
}
我想为Bar
实现Foo
特性:
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
生存期.
I found no way to specify lifetimes inside that associated type. In particular I want to express that the iterator cannot outlive the self
lifetime.
如何修改Foo
特征或Bar
特征实现以使其起作用?
How do I have to modify the Foo
trait, or the Bar
trait implementation, to make this work?
推荐答案
对于您的问题,有两种解决方案.让我们从最简单的一个开始:
There are a two solutions to your problem. Let's start with the simplest one:
trait Foo<'a> {
type Item: AsRef<Path>;
type Iter: Iterator<Item = Self::Item>;
fn get(&'a self) -> Self::Iter;
}
这要求您在使用特征的任何地方注释生命周期.实现特征时,需要执行通用实现:
This requires you to annotate the lifetime everywhere you use the trait. When you implement the trait, you need to do a generic implementation:
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()
}
}
当您需要为通用参数提供特征时,还需要确保对特征对象的任何引用都具有相同的生存期:
When you require the trait for a generic argument, you also need to make sure that any references to your trait object have the same lifetime:
fn fooget<'a, T: Foo<'a>>(foo: &'a T) {}
实施特征以引用您的类型
代替为您的类型实现特征,而将其实现为对您类型的引用.这种特质永远不需要这样了解一生.
Implement the trait for a reference to your type
Instead of implementing the trait for your type, implement it for a reference to your type. The trait never needs to know anything about lifetimes this way.
那么trait函数必须按值接受其参数.在您的情况下,您将实现该特征以供参考:
The trait function then must take its argument by value. In your case you will implement the trait for a reference:
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
函数尝试调用get
两次,该函数将无法编译.
The problem with this is that the fooget
function doesn't know T
is in reality a &Bar
. When you call the get
function, you are actually moving out of the foo
variable. You don't move out of the object, you just move the reference. If your fooget
function tries to call get
twice, the function won't compile.
如果您想让fooget
函数仅接受为引用实现了Foo
特征的参数,则需要明确声明此绑定:
If you want your fooget
function to only accept arguments where the Foo
trait is implemented for references, you need to explicitly state this bound:
fn fooget_twice<'a, T>(foo: &'a T)
where
&'a T: Foo,
{}
where
子句可确保仅对为引用实现了Foo
而不是类型的引用调用此函数.两者都可以实现.
The where
clause makes sure that you only call this function for references where Foo
was implemented for the reference instead of the type. It may also be implemented for both.
从技术上讲,编译器可以自动推断fooget_twice
的生存期,因此您可以将其编写为
Technically, the compiler could automatically infer the lifetime in fooget_twice
so you could write it as
n fooget_twice<T>(foo: &T)
where
&T: Foo,
{}
但它还不够聪明还.
对于更复杂的情况,可以使用尚未实现的Rust功能:通用关联类型(GAT).在 issue 44265 中进行跟踪.
For more complicated cases, you can use a Rust feature which is not yet implemented: Generic Associated Types (GATs). Work for that is being tracked in issue 44265.
这篇关于如何在关联类型中指定生命周期参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!