rust 返回引用字符串的future

wbgh16ku  于 2023-03-12  发布在  其他
关注(0)|答案(1)|浏览(151)

我正在尝试创建FuturesVec,以便与try_join_all一起使用。

use futures::future::try_join_all;

struct Image {
    pub file_name: String,
}

struct Storage;

impl Storage {
    async fn upload(&self, filename: &str) -> Result<String, ()> {
        Ok(filename.to_owned())
    }
}

struct ImagesRepository {
    storage: Storage,
}

impl ImagesRepository {
    async fn upload_images(&self, images: &[Image]) -> Result<Vec<String>, ()> {
        let futures = images
            .iter()
            .map(|image| {
                let path_name = format!("somedirectory/{}", &image.file_name);

                let future = self.storage.upload(path_name.as_str());

                future
            })
            .collect::<Vec<_>>();

        let results = try_join_all(futures).await?;

        Ok(results)
    }
}

但是,我遇到了以下编译器错误:

Compiling playground v0.0.1 (/playground)
error[E0515]: cannot return value referencing local variable `path_name`
  --> src/lib.rs:30:17
   |
26 |                 let future = self.storage.upload(path_name.as_str());
   |                                                  ------------------ `path_name` is borrowed here
...
30 |                 future
   |                 ^^^^^^ returns a value referencing data owned by the current function

For more information about this error, try `rustc --explain E0515`.
error: could not compile `playground` due to previous error

这是因为我向storage.upload传递了一个对path_name的引用,而path_name只存在于闭包中。
我知道我可以将storage.upload更改为使用String,但这意味着要破坏使用此函数的其他部分的代码。
有没有办法修正这个编译器错误?
Minimal example - Rust Playground

ego6inou

ego6inou1#

这其实很简单,你只需要把future Package 到另一个拥有这个字符串的future中,你可以用async块来实现,这个块用来创建一个特殊的匿名的Future实现值(就像|...|可以用来创建一个特殊的匿名的Fn*实现值一样):

.map(|image| async {
    let path_name = format!("somedirectory/{}", &image.file_name);

    self.storage.upload(path_name.as_str()).await
})

Playground
创建一个future并从它返回等待另一个future的结果通常是一个反模式,但这是一个不反模式的情况,这是因为 Package future不仅代理内部future的ready值,它还负责在内部future准备就绪后运行path_name的析构函数。
如果愿意,您甚至可以完全删除path_name变量:

.map(|image| async {
    self.storage.upload(
        &format!("somedirectory/{}", &image.file_name)
    ).await
})

相关问题