微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

嵌套迭代器上的 self 的生命周期问题“返回此值需要将 `*self` 借用于 `'a”

如何解决嵌套迭代器上的 self 的生命周期问题“返回此值需要将 `*self` 借用于 `'a”

我正在尝试编写一个特征,它接收 Iter<Item = T> 的工作项、过滤器,然后应用任何未完成的内容,并记录结果。该特征包含一些状态(与外部服务的连接)。由于方法的定义是特征的一部分,返回类型是 Box<dyn Iter<Item = (Status,Work)> 的变体,作为对目前无法在特征中使用 -> impl Iterator 的让步。

我去掉了 trait DoesWork 以保持代码简单,但假设整个 impl OneKindOfRunnerimpl DoesWork for OneKindOfRunner,请(in the Rust playground):

struct OneKindOfRunner {
    // conn: in reality this conn is mutable,and causes to need mut refs
    // to the OneKindOfRunner. The WorkRunner keeps a state,and that is
    // in a database backed by this conn,so work,filter and do_one_work
    // all need to communicate with the database (hence self)
    //
    // I don't kNow if I can reasonably implement copy()
    // as E0505 suggests,I prefer not right Now.
}

#[derive(Debug)]
struct Work {
    // some static stuff,no mutable state,really.
}

type WorkStatus = (bool,Work); // does the work need to happen?
type WorkResult = (bool,Work); // did we do the work successfully?

// In the real app,OneKindOfRunner implements a Runner
// trait,hence the Box<>ed dyn return types.
impl OneKindOfRunner {
    fn new() -> Self {
        OneKindOfRunner {}
    }

    fn do_one_work<'a>(&'a mut self,work_item: Work) -> WorkResult {
        (true,work_item) // return tuple indicating success or not (distinct from Result<T,E>)
    }

    fn filter_pending_work<'a>(
        &'a mut self,work: impl Iterator<Item = Work> + 'a,) -> Box<dyn Iterator<Item = WorkResult> + 'a> {
        Box::new(work.map(|w| (false,w)).into_iter())
    }

    fn work<'a>(
        &'a mut self,) -> Result<Box<dyn Iterator<Item = WorkResult> + 'a>,()> {
        Ok(Box::new(
            self.filter_pending_work(work)
                .map(move |(_status,work)| self.do_one_work(work))
                .into_iter(),))
    }
}

fn main() {
    let work = vec![Work {},Work {},Work {}].into_iter();
    let mut runner = OneKindOfRunner::new();

    match runner.work(work) {
        Ok(results) => {
            for (success,work) in results {
                println!("Result was {} for work {:?}",success,work)
            }
        }
        Err(_) => panic!("something err'd"),};
}

代码错误如下:

error[E0505]: cannot move out of `self` because it is borrowed
  --> src/main.rs:43:22
   |
37 |       fn work<'a>(
   |               -- lifetime `'a` defined here
...
41 | /         Ok(Box::new(
42 | |             self.filter_pending_work(work)
   | |             ---- borrow of `*self` occurs here
43 | |                 .map(move |(_status,work)| self.do_one_work(work))
   | |                      ^^^^^^^^^^^^^^^^^^^^^^ ---- move occurs due to use in closure
   | |                      |
   | |                      move out of `self` occurs here
44 | |                 .into_iter(),45 | |         ))
   | |__________- returning this value requires that `*self` is borrowed for `'a`

无论是否使用 #43 上的 move,我都找不到使这项工作起作用的方法

我认为 &'a mut selfResult<Box<dyn Iterator<Item = WorkResult> + 'a>,()> 将确保结果的生命周期(这意味着对迭代器闭包的依赖?)与 self (例如,我必须在允许 self 超出范围之前使用迭代器,无论是谁调用我的 work() 函数

我认为问题出在使用 self.<some fn> 两次(嵌套),我不知道有什么好的替代方法

实际上,我们不想消耗 Iter<Item = Work>,并且能够干净地 map() 覆盖它一次。

fn work<'a>(
    &'a mut self,()> {
    Ok(Box::new(
        self.filter_pending_work(work)
            .map(move |(_status,work)| self.do_one_work(work))
            .into_iter(),))
}

在框外分配 self.filter_pending_work(work) 的结果没有帮助,删除 move (_status,work) 会导致一些变化:

44 | |                 .map(|(_status,work)| self.do_one_work(work))
   | |                      ^^^^^^^^^^^^^^^^^ ---- second borrow occurs due to use of `self` in closure
   | |                      |
   | |                      closure construction occurs here
45 | |                 .into_iter(),46 | |         ))
   | |__________- returning this value requires that `*self` is borrowed for `'a`

有什么合理的方法可以解决这个问题吗? Iterator在这里做的正确的事情,还是我应该放弃整个想法并使用 Box<Vec<Work>>?感觉 Iterator<Item = Foo>更正确使用的东西,因为 Rust 强大的 API 用于过滤和映射,但尝试使用迭代器(而不是仅仅使用into_iter() 上的 Vec<T> 真的很痛苦。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。