简体   繁体   English

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

[英]How to return a struct with a reference to self in Rust?

I've implemented a struct which has a list of crontab entries, each of which knows its own recurrence (such as */5 * * * * in crontab): 我已经实现了一个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>,
}

Based on the current time you can get the next occurrence of a command: 根据当前时间,您可以获得下一个命令:

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

I'm trying to write a function on Crontab to get the Entry which will run next (that is, for which recurrence.next_match() is the lowest). 我正在尝试在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,
}

This generates the error: 这会生成错误:

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<'_>`

Similar variants I've tried fail to compile with messages such as "cannot move out of borrowed content" (if changing the return type to &Run<'a> ) or that the &entry does not live long enough. 我尝试过的类似变体无法使用诸如“无法移出借来的内容”之类的消息进行编译(如果将返回类型更改为&Run<'a> )或者&entry生存时间不够长。

It seems to make most sense that the Run should have a reference to rather than a copy of the Entry , but I'm not sure how to juggle both the lifetimes and references to get to that point (and I don't know whether 'a refers to the same lifetime in both structs). 似乎最有意义的是Run应该引用而不是Entry的副本,但我不确定如何兼顾生命周期和引用以达到这一点(我不知道是否'a指的是两种结构中相同的寿命)。 What am I missing here? 我在这里错过了什么?

As described in Is there any way to return a reference to a variable created in a function? 如有没有办法返回对函数中创建的变量的引用? , you cannot create a value in a function and return a reference to it. ,您无法在函数中创建值并返回对它的引用。 Nothing would own the result of your iterator chain, thus the reference would point at invalid data. 没有什么会拥有迭代器链的结果,因此引用将指向无效数据。

That doesn't even really matter: as pointed out in the comments, you cannot call into_iter on self.entries because you cannot move out of borrowed content to start with, as described in Cannot move out of borrowed content . 甚至不真正的问题:如在评论中指出,你不能叫into_iterself.entries ,因为你不能搬出借来的内容入手,如在不能迁出借来的内容 This means that we cannot have an owned value of an Entry as the result of the iterator chain to start with. 这意味着我们不能拥有一个Entry的拥有值作为迭代器链的结果。

Crontab owns the Entry ; Crontab拥有Entry ; as soon as the Crontab moves, any reference to any Entry becomes invalid. 一旦Crontab移动,对任何Entry任何引用都将变为无效。 This means that any references need to be tied to how long self lives; 这意味着任何引用都需要与self生存时间联系在一起; the generic lifetime 'a cannot come into play: 通用生命周期'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()
}

Or the explicit version: 或者显式版本:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM