rust - 如何使用异步回调编写异步递归 walkdir 函数
问题描述
我正在尝试编写一个异步函数,它将递归地遍历文件系统树,并为找到的每个文件调用一个异步回调。这是为了学习,我没有真正的用例。
这是我到目前为止所拥有的:
use async_std::{
fs::{self, *},
path::*,
prelude::*,
}; // 1.5.0, features = ["unstable"]
use futures::{
executor::block_on,
future::{BoxFuture, FutureExt},
}; // 0.3.4
use std::{marker::Sync, pin::Pin};
fn main() {
fn walkdir<F>(path: String, cb: &'static F) -> BoxFuture<'static, ()>
where
F: Fn(&DirEntry) -> BoxFuture<()> + Sync + Send,
{
async move {
let mut entries = fs::read_dir(&path).await.unwrap();
while let Some(path) = entries.next().await {
let entry = path.unwrap();
let path = entry.path().to_str().unwrap().to_string();
if entry.path().is_file().await {
cb(&entry).await
} else {
walkdir(path, cb).await
}
}
}
.boxed()
}
let foo = async {
walkdir(".".to_string(), &|entry: &DirEntry| async {
async_std::println!(">> {}\n", &entry.path().to_str().unwrap()).await
})
.await
};
block_on(foo);
}
我通过某种反复试验得到了这一步,但现在我被这个错误困在异步关闭回调上
warning: unused import: `path::*`
--> src/main.rs:3:5
|
3 | path::*,
| ^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
warning: unused import: `pin::Pin`
--> src/main.rs:10:25
|
10 | use std::{marker::Sync, pin::Pin};
| ^^^^^^^^
error[E0308]: mismatched types
--> src/main.rs:33:54
|
33 | walkdir(".".to_string(), &|entry: &DirEntry| async {
| ______________________________________________________^
34 | | async_std::println!(">> {}\n", &entry.path().to_str().unwrap()).await
35 | | })
| |_________^ expected struct `std::pin::Pin`, found opaque type
|
= note: expected struct `std::pin::Pin<std::boxed::Box<dyn core::future::future::Future<Output = ()> + std::marker::Send>>`
found opaque type `impl core::future::future::Future`
解决方案
use async_std::{
fs::{self, *},
path::*,
prelude::*,
}; // 1.5.0
use futures::{future::{Future, FutureExt, LocalBoxFuture}, executor}; // 0.3.4
fn main() {
async fn walkdir<R>(path: impl AsRef<Path>, mut cb: impl FnMut(DirEntry) -> R)
where
R: Future<Output = ()>,
{
fn walkdir_inner<'a, R>(path: &'a Path, cb: &'a mut dyn FnMut(DirEntry) -> R) -> LocalBoxFuture<'a, ()>
where
R: Future<Output = ()>,
{
async move {
let mut entries = fs::read_dir(path).await.unwrap();
while let Some(path) = entries.next().await {
let entry = path.unwrap();
let path = entry.path();
if path.is_file().await {
cb(entry).await
} else {
walkdir_inner(&path, cb).await
}
}
}.boxed_local()
}
walkdir_inner(path.as_ref(), &mut cb).await
}
executor::block_on({
walkdir(".", |entry| async move {
async_std::println!(">> {}", entry.path().display()).await
})
});
}
显着变化:
- 接受
AsRef<Path>
而不是一个String
和一个通用闭包而不是一个特征对象引用 - 将闭包类型更改
FnMut
为更宽松 - 闭包返回任何未来的类型。
- 有一个内部实现函数隐藏了递归异步函数所需的丑陋 API。
- 回调采用
DirEntry
值而不是引用。
也可以看看:
推荐阅读
- html - 对齐按钮内的项目
- c++ - 尽管安装了驱动程序,Ubuntu 上的 Qt 5.9.5 在“/usr/include/libdrm”中找不到“GL/gl.h”
- azure - 在代码中组合无服务器 Azure 函数但独立运行
- java - 从 ALB 到 20 多个容器的 ECS Fargate 路由
- javascript - 如何在 Web 单页应用中使用 Firebase Analytics 跟踪页面浏览量?
- lua - 了解 LUA 回调
- php - wordpress 中的自定义导航栏。如何正确地设计它?
- php - PHPMailer 发送邮件很慢
- java - UniRest 和 Spring RestTemplate 给出 http 400 错误请求有什么区别?
- typescript - var 声明上的 Jest/Istanbul 单元测试分支覆盖率