如何在Tokio中使用async/await语法?

7

我正在尝试在Rust中使用async/await处理进程。我正在使用tokiotokio-process

#![feature(await_macro, async_await, futures_api)]

extern crate tokio;
extern crate tokio_process;

use std::process::Command;
use tokio_process::CommandExt;

fn main() {
    tokio::run_async(main_async());
}

async fn main_async() {
    let out = Command::new("echo")
        .arg("hello")
        .arg("world")
        .output_async();
    let s = await!(out);
}

这是我收到的错误信息:

error[E0277]: the trait bound `tokio_process::OutputAsync: std::future::Future` is not satisfied
  --> src/main.rs:21:13
   |
21 |     let s = await!(out);
   |             ^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `tokio_process::OutputAsync`
   |
   = note: required by `std::future::poll_with_tls_waker`
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

error[E0277]: the trait bound `tokio_process::OutputAsync: std::future::Future` is not satisfied
  --> src/main.rs:21:13
   |
21 |     let s = await!(out);
   |             ^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `tokio_process::OutputAsync`
   |
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

我该如何正确做到这一点?

1个回答

12
TL;DR:使用 Tokio 0.2 或更新版本,它应该可以正常工作。
Tokio 0.1 及其相关 crate 是使用 futures 0.1 crate 实现的。这个 crate 中的 Future trait 在概念上与标准库中的 Future trait 版本相似,但在细节上有很大不同。async / await 语法是围绕标准库中的 Future trait 版本构建的。
Tokio 0.2 及其相关 crate 是使用标准库 Future 实现的,并已重构以更好地支持 async / await 语法。
Tokio 0.2
[dependencies]
tokio = { version = "0.2", features = ["full"] }

use tokio::process::Command;

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let out = Command::new("echo")
        .arg("hello")
        .arg("world")
        .output()
        .await?;

    let s = String::from_utf8_lossy(&out.stdout);

    println!("{}", s);
    Ok(())
}

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.05s
     Running `target/debug/tokio2`
hello world

测试环境:

  • Rustc 1.39.0

Tokio 0.1

你需要在实现了 futures 0.1 crate 的 trait 和标准库之间进行翻译translate between a Future implemented against the trait from the futures 0.1 crate and from the standard library。此外,你需要启动 Tokio 运行时服务,最好同时支持 Tokio 0.1 和 Tokio 0.3。这就是 tokio-compat 的作用所在:

[dependencies]
futures = { version = "0.3", features = ["compat"] }
tokio-compat = "0.1"
tokio-process = "0.2"

use futures::compat::Future01CompatExt;
use std::process::Command;
use tokio_process::CommandExt;

fn main() {
    tokio_compat::run_std(main_async());
}

async fn main_async() {
    let out = Command::new("echo")
        .arg("hello")
        .arg("world")
        .output_async();

    // Convert future from 0.1 to 0.3
    let s = out.compat().await;

    println!("{:?}", s);
}

% cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.07s
     Running `target/debug/tt`
Ok(Output { status: ExitStatus(ExitStatus(0)), stdout: "hello world\n", stderr: "" })

使用 Rust 1.43.0 进行测试。

另请参见:


当我使用Tokio v0.1.22和Reqwest v0.10.0-alpha.2时,运行tokio::run({async fn reqwest::get(url).await})时出现错误:Error(Connect, Custom { kind: Other, error: "no current reactor" })。 - CS QGB
@CSQGB reqwest alpha 需要 tokio alpha - Shepmaster
Tokio 0.1与reqwest alpha不兼容,除非我使用tokio v0.2.0-alpha,是吗? - CS QGB
你好 Shepmaster。tokio-process 0.3.0-alpha.2 与 reqwest 0.10.0-alpha.2 不兼容。我遇到了错误:无法选择 futures-core-preview 的版本。 - CS QGB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接