调用在闭包中采用 `&self` 的方法时的生命周期问题

问题描述 投票:0回答:1

我正在尝试将我的代码从使用 join_all 处理一组期货转换为流,因为这似乎是一种更强大的方法,因为它允许我在未来的结果可用时立即处理它们,而不是等待所有结果。

然而,我遇到了一生无法解决的问题。

游乐场的最小复制:

use std::sync::Arc;
use futures::{Stream, StreamExt, stream::BoxStream};

struct Querier {
    id: u32,
}

impl Querier {
    fn query<'a>(&'a self) -> impl Stream<Item = u32> + 'a {
        futures::stream::once(async move { self.id })
    }
}

fn query_all<'a>() -> BoxStream<'a, u32> {
    let queriers = vec![
        Arc::new(Querier { id: 1 }),
        Arc::new(Querier { id: 2 }),
    ];

    futures::stream::iter(queriers.into_iter())
        .flat_map(move |q| {
            let q = q.clone();
            q.query()
        })
        .boxed()
}

#[tokio::main]
async fn main() {
    let _stream = query_all();
}

游乐场

如您所见,

box
ing 流和/或克隆
Querier
没有帮助。我想我明白为什么了,这是因为查询器仍然在本地定义并且
query
的返回与它相关。

在查询函数中用

&self
替换
Arc<Self>
是可行的,但我想学习其他替代方法,因为这是一个我无法解决的反复出现的问题,并且查询可能来自图书馆。

有没有办法在保持查询器实例化本地的同时解决这个问题?


附言取得一些进展:this 编译但它不再返回流中的所有元素。

rust lifetime
1个回答
0
投票

有些东西必须拥有

Querier
,它不可能是:

  1. query_all
    因为你想从中返回
    Stream
    所以本地值不能被引用
  2. 关闭
    |q| q.query
    同样的原因
  3. Stream
    futures::stream::iter(queriers)
    因为它放弃了对其产生的价值的所有权
  4. query
    或其中的任何内容,因为您只给它一个参考

不幸的是,在

Querier
返回后,我们没有
query_all
的有效所有者,这意味着对它的任何引用都是悬而未决的和无效的,但是借用检查器已经支持你并且不允许你将代码编译为是。

要修复它,你必须确定什么应该拥有

Querier
,有2个选项:

  1. 共享所有权使用
    Arc
    ,这是你已经找到的解决方案。
  2. 但实际上我们只需要一件事来拥有它,那就是
    query
    生成的流所以你可以简单地给它项目而不是对它的引用:
    fn query(self) -> impl Stream<Item = u32> {
        use futures::stream::once;
        once(async move { self.id }).chain(once( self.id * 2))
    }
    
© www.soinside.com 2019 - 2024. All rights reserved.