我再次与生命斗争。或者实际上,我有点赢了这场斗争,但我不确定结果是否是处理它的预期方式。
假设我有一个有两个生命周期的结构:Inner<'a, 'b>
。现在我想写一个定义new(inner: &Inner) -> Self
方法的特征。实现者应该可以自由地在内部存储对Inner
的引用,并定义其他方法来处理它。
我想出了这个(它有效!)但我有几个问题
struct Inner<'a, 'b>{
foo: &'a str,
bar: &'b str
}
trait Worker<'data, 'a, 'b> {
fn new (inner: &'data Inner<'a, 'b>) -> Self;
fn work_with_inner () { println!("works on inner");}
}
struct SomeWorker<'inner, 'a:'inner, 'b:'inner> {
inner: &'inner Inner<'a, 'b>
}
impl<'data, 'a, 'b> Worker<'data, 'a, 'b> for SomeWorker<'data, 'a, 'b> {
fn new (inner: &'data Inner<'a, 'b>) -> Self {
SomeWorker {
inner: inner
}
}
}
fn main () {
}
就生命周期而言,这可以简化吗?特别是,我想知道这个特性是否真的需要定义所有这些生命周期,或者是否只能在结构上定义它们?
如果无法忽略特征的生命周期,那么这意味着最佳做法是在特征上指定所有可能的生命周期,以便为实施者提供最大的灵活性吗?我的意思是,如果SomeWorker
结构不想存储对Inner
的引用,那么包括特征在内的整个事情可能会简单得多。
看,根本没有生命。
struct Inner<'a, 'b>{
foo: &'a str,
bar: &'b str
}
trait Worker {
fn new (inner: &Inner) -> Self;
fn work_with_inner () { println!("works on inner");}
}
struct SomeWorker;
impl Worker for SomeWorker {
fn new (inner: &Inner) -> Self {
SomeWorker
}
}
fn main () {
}
这就是为什么我要问自己作为一个特质作者我应该假设所有参考的方法都可能最终由特质实现者存储在一个字段中,因此我需要指定所有的生命周期。实现这一点的特性。
答案 0 :(得分:5)
没有一个通用的解决方案。作为特质作者,您必须考虑您尝试做什么以及您想要实现的目标。
如果您希望能够将值生命周期与结构的生命周期参数相关联,则必须将生命周期放在特征上。这通常会完成,因为你的特性有多种方法,这些方法预计会在相同的生命周期值上运行。这可能类似于getter / setter对。在我写的一些代码中,我在传递&str
引用了一段时间,然后“敲定”它们。如果您因任何原因需要存储引用,那么您将需要具有该特征的生命周期。
在您的情况下,您有一个构造函数方法,需要知道结构的生命周期。如果它真的与众不同,你可以将该功能与其他特征分开。在您的示例中,work_with_inner
方法不接受self
参数,因此非常不同。如果您使用self
但不需要与Inner
的生命周期进行互动,那么它仍然可以提供帮助:
trait WorkerBuilder<'a, 'b> {
fn new(inner: Inner<'a, 'b>) -> Self;
}
trait Worker {
fn do_work(&self);
}
#[derive(Debug)]
struct Inner<'a, 'b>{
foo: &'a str,
bar: &'b str,
}
// This does track `Inner`
#[derive(Debug)]
struct SomeWorker<'a, 'b>(Inner<'a, 'b>);
impl<'a, 'b> WorkerBuilder<'a, 'b> for SomeWorker<'a, 'b> {
fn new(inner: Inner<'a, 'b>) -> SomeWorker<'a, 'b> {
SomeWorker(inner)
}
}
impl<'a, 'b> Worker for SomeWorker<'a, 'b> {
fn do_work(&self) { println!("Doing work, {:?}", self.0) }
}
// This doesn't track `Inner`
#[derive(Debug)]
struct DumbWorker;
impl<'a, 'b> WorkerBuilder<'a, 'b> for DumbWorker {
fn new(inner: Inner<'a, 'b>) -> DumbWorker {
DumbWorker
}
}
fn main () {}
你会看到我也应用了可以做的一件事来减少生命周期的数量。如果你的结构只是引用(或引用和其他小Copy
类型),则不需要传递对那个结构的引用。引用是可复制的,跟踪包含结构的生命周期是没有用的。
编辑 - 我不觉得“构造函数”方法通常在特征中有用。您经常需要提供不同的设置或参数,这就是您首先使用不同类型的原因。也许你的真实代码在特征中使用的不是构造函数。