Rust tokio非阻塞读子进程stdout调用for_each报错及Trait导入问题
问题修复方案
编译错误原因
Tokio 1.x版本中,tokio::io::Lines本身没有实现Stream trait,无法直接调用StreamExt提供的for_each方法,官方文档明确提示该类型需要转换为LinesStream后才能作为Stream使用。
修复方法
方案1:用循环逐行读取(更简单,无需额外依赖)
直接使用Lines自带的next_line异步方法循环读取,修改代码中处理stdout的部分即可:
use std::process::Stdio; use tokio::{io::AsyncBufReadExt, io::BufReader, process::Command}; #[tokio::main] async fn main() { let mut child = Command::new("sudo") .arg("ls") .stdout(Stdio::piped()) .spawn() .expect("Command failed"); let stdout = child.stdout.take().unwrap(); let mut lines = BufReader::new(stdout).lines(); while let Ok(Some(line)) = lines.next_line().await { println!("> {:?}", line); } }
方案2:使用Stream的for_each方法
如果需要保留Stream链式调用的写法,按以下步骤修改:
- 在
Cargo.toml中添加tokio-stream依赖:
[dependencies] futures = "0.3.15" tokio = { version = "1", features = ["full"] } tokio-stream = "0.1"
- 修改代码导入对应依赖并转换类型:
use std::process::Stdio; use tokio::{io::AsyncBufReadExt, io::BufReader, io::LinesStream, process::Command}; use tokio_stream::StreamExt; #[tokio::main] async fn main() { let mut child = Command::new("sudo") .arg("ls") .stdout(Stdio::piped()) .spawn() .expect("Command failed"); let stdout = child.stdout.take().unwrap(); LinesStream::new(BufReader::new(stdout).lines()) .for_each(|s| async move { println!("> {:?}", s) }) .await; }
快速查找需要导入的Trait的方法
- 参考编译器报错:Rust编译器会对未导入Trait的方法调用给出明确的导入提示,直接按照提示导入对应Trait即可。
- 查阅官方文档:对应类型的官方文档页会列出该类型实现的所有Trait,以及每个Trait提供的方法,搜索目标方法名即可找到归属的Trait。
- 使用开发工具辅助:安装
rust-analyzer插件后,输入方法名会自动提示需要导入的Trait,支持一键导入,无需手动查找。 - 导入库的prelude模块:大部分常用库都提供prelude模块,例如
use futures::prelude::*;、use tokio::prelude::*;,可以一次性导入该库绝大多数常用Trait,减少逐个导入的麻烦。
注:你提到的
tokio::prelude不存在属于拼写误解,Tokio 1.x版本是存在该模块的,正常导入即可使用。
内容的提问来源于stack exchange,提问作者eletvon
相关产品推荐
相关产品推荐

