有没有办法在这里省略特征的生命周期?

Is there a way to omit the lifetimes for the trait here?

我又在和生生世世搏斗了。或者实际上,我有点赢了这场战斗,但我不确定结果是否是预期的处理方式。

假设我有一个具有两个生命周期的结构: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 () {
}

围栏:http://is.gd/A3ol4w

  1. 关于生命周期,这个可以简化吗?特别是,我想知道特征是否真的需要定义所有这些生命周期,或者是否有办法只在结构上定义它们?

  2. 如果没有办法省略特征的生命周期,这是否意味着最佳实践是指定特征的所有可能生命周期以便为实施者提供最大的灵活性?我的意思是,如果 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 () {
}

围栏:http://is.gd/NzigjX

这就是为什么我问自己,作为一个 trait 作者,我是否应该假设所有采用引用的方法最终都可能被 trait 实现者存储在一个字段中,因此我需要在特性使实现者成为可能。

没有万能的解决方案。作为特质作者,您必须考虑您正在尝试做什么以及您想要实现什么。

如果您希望能够将值生命周期与结构的生命周期参数相关联,那么您必须将生命周期放在特征上。这将 通常 完成,因为你的特征有多个方法,这些方法预计在生命周期内对相同的值进行操作。这可能类似于 getter / setter 对。在我编写的一些代码中,我传递了 &str 引用,在 "finalizing" 它们之前我保留了一段时间。如果您出于任何原因需要存储引用,那么您将需要在特征上有生命周期。

在您的情况下,您有一个构造函数方法需要知道生命周期(如果结构需要的话)。您可以将该功能与其余特征分开,如果它确实不同的话。在您的示例中,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 类型),则无需传递对 that 结构的引用。引用是可复制的,跟踪包含结构的生命周期没有用。


社论 — 我不认为 "constructor" 方法在特征中通常有用。您经常希望提供不同的集合或参数,这就是为什么您首先要有不同类型的原因。也许你的真实代码在特征中使用了构造函数以外的东西。