如何在Rust中返回一个引用self的结构?

时间:2018-03-12 22:36:13

标签: rust

implemented一个struct,其中有一个crontab条目列表,每个条目都知道它自己的重复发生(例如crontab中的*/5 * * * *):

extern crate chrono;

use chrono::NaiveDateTime;

pub struct Crontab<'a> {
    entries: Vec<Entry<'a>>,
}

pub struct Entry<'a> {
    pub recurrence: Recurrence,
    pub command: &'a str,
}

pub struct Recurrence {
    minutes: Vec<u8>,
    hours: Vec<u8>,
    days_of_month: Vec<u8>,
    months: Vec<u8>,
    days_of_week: Vec<u8>,
}

根据当前时间,您可以获得下一次命令:

impl Recurrence {
    pub fn next_match(&self, after: NaiveDateTime) -> NaiveDateTime {
        unimplemented!()
    }
}

我正在尝试在Crontab上编写一个函数来获取接下来要运行的Entry(也就是recurrence.next_match()最低的那个)。

impl<'a> Crontab<'a> {
    fn next_run(&self, from: NaiveDateTime) -> Run<'a> {
        &self.entries
            .into_iter()
            .map(|entry| Run {
                entry: &entry,
                datetime: entry.recurrence.next_match(from),
            })
            .min_by(|this, other| this.datetime.cmp(&other.datetime))
            .unwrap()
    }
}

struct Run<'a> {
    entry: &'a Entry<'a>,
    datetime: NaiveDateTime,
}

这会产生错误:

error[E0308]: mismatched types
  --> src/main.rs:30:9
   |
29 |       fn next_run(&self, from: NaiveDateTime) -> Run<'a> {
   |                                                  ------- expected `Run<'a>` because of return type
30 | /         &self.entries
31 | |             .into_iter()
32 | |             .map(|entry| Run {
33 | |                 entry: &entry,
...  |
36 | |             .min_by(|this, other| this.datetime.cmp(&other.datetime))
37 | |             .unwrap()
   | |_____________________^ expected struct `Run`, found &Run<'_>
   |
   = note: expected type `Run<'a>`
              found type `&Run<'_>`

类似的变种我尝试使用诸如“无法移出借来的内容”(如果将返回类型更改为&Run<'a>)或&entry的生存时间不够长等消息进行编译

似乎最有意义的是Run应该引用而不是Entry的副本,但我不确定如何兼顾生命周期和引用那一点(我不知道'a是否指的是两个结构中相同的生命周期)。我在这里缺少什么?

1 个答案:

答案 0 :(得分:2)

Is there any way to return a reference to a variable created in a function?中所述,您无法在函数中创建值并返回对它的引用。没有任何东西会拥有迭代器链的结果,因此引用将指向无效数据。

这并不重要:正如评论中指出的那样,您无法在into_iter上致电self.entries,因为您无法从借来的内容中退出,如{ {3}}。这意味着我们不能拥有Entry的拥有值作为迭代器链的结果。

Crontab拥有Entry;只要Crontab移动,对任何Entry的任何引用都将失效。这意味着任何引用都需要与self生存的时间相关联;通用生命周期'a无法发挥作用:

fn next_run(&self, from: NaiveDateTime) -> Run {
    self.entries
        .iter()
        .map(|entry| Run {
            entry,
            datetime: entry.recurrence.next_match(from),
        })
        .min_by(|this, other| this.datetime.cmp(&other.datetime))
        .unwrap()
}

或显式版本:

fn next_run<'b>(&'b self, from: NaiveDateTime) -> Run<'b> { /* ... */ }