在异步函数参数中声明特征对象的关联类型

Declaring Associated Type of Trait Object in Async Function Parameter

我想要一个异步处理可变数量的 (Sink, Stream) 元组的函数。

use futures::channel::mpsc;
use futures::{Sink, Stream, SinkExt, StreamExt};

async fn foo(v: Vec<(Box<dyn Sink<Error = std::io::Error>>, Box<dyn Stream<Item = u8>>)>) {
    for (mut tx, mut rx) in v {
        let _ = tx.send(0);
        let _ = rx.next().await;
    }
}

#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (tx, mut rx) = mpsc::channel(32);
    foo(vec![(Box::new(tx), Box::new(rx))]).await;
    
    Ok(())
}

但是我得到这个编译错误:

error[E0107]: wrong number of type arguments: expected 1, found 0
 --> src/main.rs:4:30
  |
4 | async fn foo(v: Vec<(Box<dyn Sink<Error = std::io::Error>>, Box<dyn Stream<Item = u8>>)>) {
  |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 type argument

编译器本身提示我以这种方式为特征对象声明关联类型。我不确定为什么它不接受它。

编译器希望您指定 Sink 的“类型参数”。这不是错误类型,而是发送到接收器的项目类型,如 Sink<Foo> 中所示。您将 u8 指定为流的类型,并且在一个和另一个之间发送不变的值,因此您可能需要一个 Sink<u8>.

一旦你这样做了,编译器接下来会抱怨你需要指定 Error 关联类型(这次是真的)。但是,如果您指定 std::io::Error,从 main()foo() 的调用将无法编译,因为 mpsc::SenderSink 的实现指定了它自己的 mpsc::SendError 作为错误类型。

最后,需要固定接收器和流,以便它们可以跨等待点存在。这是通过使用 Pin<Box<...>> 而不是 Box<...>Box::pin(...) 而不是 Box::new(...) 来完成的。

经过以上改动,编译后的版本如下所示:

use futures::channel::mpsc;
use futures::{Sink, SinkExt, Stream, StreamExt};
use std::pin::Pin;

async fn foo(
    v: Vec<(
        Pin<Box<dyn Sink<u8, Error = mpsc::SendError>>>,
        Pin<Box<dyn Stream<Item = u8>>>,
    )>,
) {
    for (mut tx, mut rx) in v {
        let _ = tx.send(0);
        let _ = rx.next().await;
    }
}

#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (tx, rx) = mpsc::channel(32);
    foo(vec![(Box::pin(tx), Box::pin(rx))]).await;

    Ok(())
}