rust - 如何使用异步回调编写异步递归 walkdir 函数

标签 rust

我正在尝试编写一个异步函数,它将递归地遍历文件系统树,并为找到的每个文件调用一个异步回调。 这是为了学习,我没有真正的用例。

这是我目前所拥有的:

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因为它更宽容
  • 闭包返回 future 的任何类型。
  • 有一个内部实现函数隐藏了递归异步函数所需的丑陋 API。
  • 回调采用DirEntry按值而不是按引用。

另见:

关于rust - 如何使用异步回调编写异步递归 walkdir 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60265831/

相关文章:

iterator - 为什么 `FromIterator` 的实现使用 `IntoIterator` 而不是 `Iterator` ?

vector - 在Vec中查找一对元素

tcp - Rust TCP如何获取字节数组长度?

rust - 为什么不能在同一结构中存储值和对该值的引用?

object - 在 Rust(0.5 和/或 trunk)中,如何创建可变对象的可变向量?

rust - 在 Vec 的中间或开头高效地插入或替换多个元素?

rust - 如何固定投影向量的元素?

rust - 一个 Rust 数组可以有多少个元素?

string - Rust:无法将整数解析为字符串,ParseIntError

request - 如何在中间件和处理程序中读取 Iron Request?