【问题标题】:How to return a struct with a reference to self in Rust?如何在 Rust 中返回一个引用 self 的结构?
【发布时间】:2018-03-12 22:36:13
【问题描述】:

我有一个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<'_>`

我尝试过的类似变体无法通过诸如“无法移出借用内容”(如果将返回类型更改为&amp;Run&lt;'a&gt;)或&amp;entry 寿命不够长等消息进行编译。

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

【问题讨论】:

  • 也许您会阅读Is there any way to return a reference to a variable created in a function?,然后阅读edit 您的问题来解释它有何不同?
  • 我没有尝试编译(请改为发布您的错误),但似乎立即出错的是.into_iter()。该调用消耗原始值。如果您希望 entries 在迭代后存在,则希望 iter 迭代引用。
  • @Shepmaster 至少不同之处在于我传递了一个对我希望响应引用的对象的引用,&amp;self

标签: rust


【解决方案1】:

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

这甚至都不重要:正如 cmets 中所指出的,您不能在 self.entries 上调用 into_iter,因为您无法从借用的内容中移出,如 Cannot move out of borrowed content 中所述。这意味着我们不能拥有 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> { /* ... */ }

【讨论】:

  • 太棒了!移出借用内容的错误指向self.entries这一行,所以我认为它与into_iter调用无关。
猜你喜欢
  • 2020-11-04
  • 1970-01-01
  • 2023-02-05
  • 1970-01-01
  • 2019-07-31
  • 2020-07-07
  • 2015-12-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多