您的问题有两种解决方案。让我们从最简单的开始:
为你的特质增添一生
trait Foo<'a> {
type Item: AsRef<Path>;
type Iter: Iterator<Item = Self::Item>;
fn get(&'a self) -> Self::Iter;
}
这要求您在使用该特征的任何地方都注释生命周期。当您实现该特征时,您需要进行通用实现:
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()
}
}
当您需要通用参数的特征时,您还需要确保对特征对象的任何引用都具有相同的生命周期:
fn fooget<'a, T: Foo<'a>>(foo: &'a T) {}
实现对您的类型的引用的特征
不要为您的类型实现该特征,而是为了对您的类型的引用而实现它。该特质永远不需要以这种方式了解有关生命周期的任何信息。
然后,特征函数必须按值获取其参数。在您的情况下,您将实现该特征以供参考:
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()
}
}
Your fooget
函数现在简单地变成
fn fooget<T: Foo>(foo: T) {}
这样做的问题是fooget
函数不知道T
实际上是一个&Bar
。当您致电get
函数,你实际上是从foo
多变的。您无需移出对象,只需移动参考即可。如果你的fooget
函数尝试调用get
两次,该函数将无法编译。
如果你想要你的fooget
函数只接受参数,其中Foo
Trait 是为了引用而实现的,您需要显式地声明这个边界:
fn fooget_twice<'a, T>(foo: &'a T)
where
&'a T: Foo,
{}
The where
子句确保您仅在引用时调用此函数Foo
是为了参考而不是类型而实现的。也可以对两者实施。
从技术上讲,编译器可以自动推断生命周期fooget_twice
所以你可以把它写成
fn fooget_twice<T>(foo: &T)
where
&T: Foo,
{}
但它还不够聪明yet.
对于更复杂的情况,您可以使用尚未实现的 Rust 功能:通用关联类型(服务贸易总协定)。为此所做的工作正在被跟踪问题 44265.