I want to write a program which recursively deletes a directory with async functions in Rust 1.39.
As a first step I have tried the following code, but it doesn't compile:
use std::env;
use failure::Error;
use futures::Future;
use std::path::PathBuf;
use tokio::prelude::*;
fn walk(path: PathBuf) -> Box<dyn Future<Item = (), Error = Error> + Send> {
let task = tokio::fs::read_dir(path)
.flatten_stream()
.for_each(move |entry| {
let filepath = entry.path();
if filepath.is_dir() {
future::Either::A(walk(filepath))
} else {
println!("File: {:?}", filepath);
future::Either::B(future::ok(()))
}
})
.map_err(Error::from)
.and_then(|_| {
println!("All tasks done");
});
Box::new(task)
}
fn main() -> Result<(), std::io::Error> {
let args: Vec<String> = env::args().collect();
let dir = &args[1];
let t = walk(PathBuf::from(&dir)).map_err(drop);
tokio::run(t);
Ok(())
}
When I run cargo build
I get the following output:
error[E0220]: associated type `Item` not found for `core::future::future::Future`
--> src\main.rs:10:42
|
10 | fn walk(path: PathBuf) -> Box<dyn Future<Item = (), Error = Error> + Send> {
| ^^^^^^^^^ associated type `Item` not found
error[E0220]: associated type `Error` not found for `core::future::future::Future`
--> src\main.rs:10:53
|
10 | fn walk(path: PathBuf) -> Box<dyn Future<Item = (), Error = Error> + Send> {
| ^^^^^^^^^^^^^ associated type `Error` not found
error[E0191]: the value of the associated type `Output` (from the trait `core::future::future::Future`) must be specified
--> src\main.rs:10:31
|
10 | fn walk(path: PathBuf) -> Box<dyn Future<Item = (), Error = Error> + Send> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated type `Output` must be specified
Cargo.toml:
[dependencies]
async-std = "1.0.1"
failure = "0.1.6"
futures = "0.3.1"
tokio = "0.1.22"
Any help?
You are using futures 0.3, which tokio 0.1 doesn't support yet. Instead, import Tokio and use its prelude
module, which re-exports the version of futures
that it does support:
use std::{env, path::PathBuf};
use tokio::prelude::*; // 0.1.22
type Error = Box<dyn std::error::Error + Send + Sync>;
fn walk(path: PathBuf) -> Box<dyn Future<Item = (), Error = Error> + Send> {
let task = tokio::fs::read_dir(path)
.flatten_stream()
.map_err(Error::from)
.for_each(|entry| {
let filepath = entry.path();
if filepath.is_dir() {
future::Either::A(walk(filepath))
} else {
println!("File: {:?}", filepath);
future::Either::B(future::ok(()))
}
})
.inspect(|_| {
println!("All tasks done");
});
Box::new(task)
}
fn main() -> Result<(), std::io::Error> {
let args: Vec<String> = env::args().collect();
let dir = &args[1];
let t = walk(PathBuf::from(&dir)).map_err(drop);
tokio::run(t);
Ok(())
}
You also need to convert the error after flatten_stream
and cannot use and_then
with println!
as it doesn't return a future. Use inspect
for side-effect debugging things.
Idiomatically, you don't need to collect all the arguments just to use one (use Iterator::nth
) and you don't need to require a PathBuf
as an argument. It's unclear why you return a Result
from main
as it can never be an Err
.
See also:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.